Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/agentic-assets_researchbar.json
T

1 line
2.2 MiB
Plaintext

{"repo": "agentic-assets/researchbar", "files": {"Sources/CodexBar/UsageStore.swift": {"e531e1c8a1aac332f8cc40b6614afc42cfd08663": {"t": 1785745890.7829762, "n": 74660, "h": "49f080384f7a04a5", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.backgroundWorkSettingsObservationToken\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refreshForSettingsChange()\n }\n }\n }\n\n var backgroundWorkSettingsObservationToken: Int {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n return 0\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n struct AccountInfoCacheEntry {\n let account: AccountInfo\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored var providerRefreshCoordinator = ProviderRefreshCoordinator<UsageProvider>()\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored var accountInfoCache: [UsageProvider: AccountInfoCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var memoryPressureReliefTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var storageRefreshInFlightRequestKey: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshRequestKey: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored let accountInfoCacheTTL: TimeInterval = 30\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: self.freshCodexVisibleAccountsForSnapshotHydration())\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?,\n coalesceProviderRefreshesOverride: Bool? = nil) async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase = Self.refreshPhase(hasCompletedInitialRefresh: self.hasCompletedInitialRefresh)\n let openAIWebRefreshPhase = Self.openAIWebRefreshPhase(\n providerRefreshPhase: refreshPhase,\n startupConnectivityRetryAttempt: startupConnectivityRetryAttempt)\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask {\n await self.refreshProvider(\n provider,\n coalesceIfRefreshing: coalesceProviderRefreshesOverride ??\n (ProviderInteractionContext.current == .background))\n }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage,\n refreshPhase: openAIWebRefreshPhase)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": openAIWebRefreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.freshCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n if refreshPhase == .startup {\n self.scheduleMemoryPressureRelief()\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n self.scheduleMemoryPressureRelief()\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.memoryPressureReliefTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n case antigravityQuotaSummary\n case antigravityLegacy\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n var source: SessionQuotaWindowSource?\n }\n\n func postQuotaWarning(_ event: QuotaWarningEvent, provider: UsageProvider) {\n self.sessionQuotaNotifier.postQuotaWarning(\n event: event,\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"researchbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .litellm: \"LiteLLM debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n .chutes: \"Chutes debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot, .devin,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .litellm, .zed, .deepgram, .poe, .chutes:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "ab6bac9407a5c17743e0eb3ab13fe096bd3547e7": {"t": 1785757702.0584643, "n": 74660, "h": "49f080384f7a04a5", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.backgroundWorkSettingsObservationToken\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refreshForSettingsChange()\n }\n }\n }\n\n var backgroundWorkSettingsObservationToken: Int {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n return 0\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n struct AccountInfoCacheEntry {\n let account: AccountInfo\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored var providerRefreshCoordinator = ProviderRefreshCoordinator<UsageProvider>()\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored var accountInfoCache: [UsageProvider: AccountInfoCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var memoryPressureReliefTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var storageRefreshInFlightRequestKey: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshRequestKey: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored let accountInfoCacheTTL: TimeInterval = 30\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: self.freshCodexVisibleAccountsForSnapshotHydration())\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?,\n coalesceProviderRefreshesOverride: Bool? = nil) async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase = Self.refreshPhase(hasCompletedInitialRefresh: self.hasCompletedInitialRefresh)\n let openAIWebRefreshPhase = Self.openAIWebRefreshPhase(\n providerRefreshPhase: refreshPhase,\n startupConnectivityRetryAttempt: startupConnectivityRetryAttempt)\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask {\n await self.refreshProvider(\n provider,\n coalesceIfRefreshing: coalesceProviderRefreshesOverride ??\n (ProviderInteractionContext.current == .background))\n }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage,\n refreshPhase: openAIWebRefreshPhase)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": openAIWebRefreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.freshCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n if refreshPhase == .startup {\n self.scheduleMemoryPressureRelief()\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n self.scheduleMemoryPressureRelief()\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.memoryPressureReliefTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n case antigravityQuotaSummary\n case antigravityLegacy\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n var source: SessionQuotaWindowSource?\n }\n\n func postQuotaWarning(_ event: QuotaWarningEvent, provider: UsageProvider) {\n self.sessionQuotaNotifier.postQuotaWarning(\n event: event,\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"researchbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .litellm: \"LiteLLM debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n .chutes: \"Chutes debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot, .devin,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .litellm, .zed, .deepgram, .poe, .chutes:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "ee9dc729d596f318eb5b7abdd711615475daa6bd": {"t": 1785757703.8320215, "n": 74657, "h": "99e2f81a471ccddf", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.backgroundWorkSettingsObservationToken\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refreshForSettingsChange()\n }\n }\n }\n\n var backgroundWorkSettingsObservationToken: Int {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n return 0\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n struct AccountInfoCacheEntry {\n let account: AccountInfo\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored var providerRefreshCoordinator = ProviderRefreshCoordinator<UsageProvider>()\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored var accountInfoCache: [UsageProvider: AccountInfoCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var memoryPressureReliefTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var storageRefreshInFlightRequestKey: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshRequestKey: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored let accountInfoCacheTTL: TimeInterval = 30\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: self.freshCodexVisibleAccountsForSnapshotHydration())\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?,\n coalesceProviderRefreshesOverride: Bool? = nil) async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase = Self.refreshPhase(hasCompletedInitialRefresh: self.hasCompletedInitialRefresh)\n let openAIWebRefreshPhase = Self.openAIWebRefreshPhase(\n providerRefreshPhase: refreshPhase,\n startupConnectivityRetryAttempt: startupConnectivityRetryAttempt)\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask {\n await self.refreshProvider(\n provider,\n coalesceIfRefreshing: coalesceProviderRefreshesOverride ??\n (ProviderInteractionContext.current == .background))\n }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage,\n refreshPhase: openAIWebRefreshPhase)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": openAIWebRefreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.freshCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n if refreshPhase == .startup {\n self.scheduleMemoryPressureRelief()\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n self.scheduleMemoryPressureRelief()\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.memoryPressureReliefTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n case antigravityQuotaSummary\n case antigravityLegacy\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n var source: SessionQuotaWindowSource?\n }\n\n func postQuotaWarning(_ event: QuotaWarningEvent, provider: UsageProvider) {\n self.sessionQuotaNotifier.postQuotaWarning(\n event: event,\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .litellm: \"LiteLLM debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n .chutes: \"Chutes debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot, .devin,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .litellm, .zed, .deepgram, .poe, .chutes:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "de6cd3aff9f8f6573b353fd80ed7e99ce7c523ac": {"t": 1785757706.1129172, "n": 74651, "h": "2a120ae9169d67cd", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.backgroundWorkSettingsObservationToken\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refreshForSettingsChange()\n }\n }\n }\n\n var backgroundWorkSettingsObservationToken: Int {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n return 0\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n struct AccountInfoCacheEntry {\n let account: AccountInfo\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored var providerRefreshCoordinator = ProviderRefreshCoordinator<UsageProvider>()\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored var accountInfoCache: [UsageProvider: AccountInfoCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var memoryPressureReliefTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var storageRefreshInFlightRequestKey: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshRequestKey: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored let accountInfoCacheTTL: TimeInterval = 30\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: self.freshCodexVisibleAccountsForSnapshotHydration())\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?,\n coalesceProviderRefreshesOverride: Bool? = nil) async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase = Self.refreshPhase(hasCompletedInitialRefresh: self.hasCompletedInitialRefresh)\n let openAIWebRefreshPhase = Self.openAIWebRefreshPhase(\n providerRefreshPhase: refreshPhase,\n startupConnectivityRetryAttempt: startupConnectivityRetryAttempt)\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask {\n await self.refreshProvider(\n provider,\n coalesceIfRefreshing: coalesceProviderRefreshesOverride ??\n (ProviderInteractionContext.current == .background))\n }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage,\n refreshPhase: openAIWebRefreshPhase)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": openAIWebRefreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.freshCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n if refreshPhase == .startup {\n self.scheduleMemoryPressureRelief()\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n self.scheduleMemoryPressureRelief()\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.memoryPressureReliefTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n case antigravityQuotaSummary\n case antigravityLegacy\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n var source: SessionQuotaWindowSource?\n }\n\n func postQuotaWarning(_ event: QuotaWarningEvent, provider: UsageProvider) {\n self.sessionQuotaNotifier.postQuotaWarning(\n event: event,\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .litellm: \"LiteLLM debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n .chutes: \"Chutes debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot, .devin,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .litellm, .deepgram, .poe, .chutes:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "6d906d375d2e9d43425089a4cedca2f72144830f": {"t": 1785757707.8901677, "n": 74577, "h": "d347607926d94b43", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.backgroundWorkSettingsObservationToken\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refreshForSettingsChange()\n }\n }\n }\n\n var backgroundWorkSettingsObservationToken: Int {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n return 0\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n struct AccountInfoCacheEntry {\n let account: AccountInfo\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored var providerRefreshCoordinator = ProviderRefreshCoordinator<UsageProvider>()\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored var accountInfoCache: [UsageProvider: AccountInfoCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var memoryPressureReliefTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var storageRefreshInFlightRequestKey: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshRequestKey: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored let accountInfoCacheTTL: TimeInterval = 30\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: self.freshCodexVisibleAccountsForSnapshotHydration())\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?,\n coalesceProviderRefreshesOverride: Bool? = nil) async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase = Self.refreshPhase(hasCompletedInitialRefresh: self.hasCompletedInitialRefresh)\n let openAIWebRefreshPhase = Self.openAIWebRefreshPhase(\n providerRefreshPhase: refreshPhase,\n startupConnectivityRetryAttempt: startupConnectivityRetryAttempt)\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask {\n await self.refreshProvider(\n provider,\n coalesceIfRefreshing: coalesceProviderRefreshesOverride ??\n (ProviderInteractionContext.current == .background))\n }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage,\n refreshPhase: openAIWebRefreshPhase)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": openAIWebRefreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.freshCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n if refreshPhase == .startup {\n self.scheduleMemoryPressureRelief()\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n self.scheduleMemoryPressureRelief()\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.memoryPressureReliefTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n case antigravityQuotaSummary\n case antigravityLegacy\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n var source: SessionQuotaWindowSource?\n }\n\n func postQuotaWarning(_ event: QuotaWarningEvent, provider: UsageProvider) {\n self.sessionQuotaNotifier.postQuotaWarning(\n event: event,\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .litellm: \"LiteLLM debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot, .devin,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .litellm, .deepgram, .poe:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "5b8313f7343ece25abae39a87ea8b250af12c23c": {"t": 1785757730.2663462, "n": 74494, "h": "8d069c044996b3b1", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.backgroundWorkSettingsObservationToken\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refreshForSettingsChange()\n }\n }\n }\n\n var backgroundWorkSettingsObservationToken: Int {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n return 0\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n struct AccountInfoCacheEntry {\n let account: AccountInfo\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored var providerRefreshCoordinator = ProviderRefreshCoordinator<UsageProvider>()\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored var accountInfoCache: [UsageProvider: AccountInfoCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var memoryPressureReliefTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var storageRefreshInFlightRequestKey: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshRequestKey: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored let accountInfoCacheTTL: TimeInterval = 30\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: self.freshCodexVisibleAccountsForSnapshotHydration())\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?,\n coalesceProviderRefreshesOverride: Bool? = nil) async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase = Self.refreshPhase(hasCompletedInitialRefresh: self.hasCompletedInitialRefresh)\n let openAIWebRefreshPhase = Self.openAIWebRefreshPhase(\n providerRefreshPhase: refreshPhase,\n startupConnectivityRetryAttempt: startupConnectivityRetryAttempt)\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask {\n await self.refreshProvider(\n provider,\n coalesceIfRefreshing: coalesceProviderRefreshesOverride ??\n (ProviderInteractionContext.current == .background))\n }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage,\n refreshPhase: openAIWebRefreshPhase)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": openAIWebRefreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.freshCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n if refreshPhase == .startup {\n self.scheduleMemoryPressureRelief()\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n self.scheduleMemoryPressureRelief()\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.memoryPressureReliefTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n case antigravityQuotaSummary\n case antigravityLegacy\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n var source: SessionQuotaWindowSource?\n }\n\n func postQuotaWarning(_ event: QuotaWarningEvent, provider: UsageProvider) {\n self.sessionQuotaNotifier.postQuotaWarning(\n event: event,\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot, .devin,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "9490a8d5590de308bd3c12c61ff12769bd9494b1": {"t": 1785757731.7553363, "n": 74805, "h": "550d83f47d5ba796", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.backgroundWorkSettingsObservationToken\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refreshForSettingsChange()\n }\n }\n }\n\n var backgroundWorkSettingsObservationToken: Int {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n return 0\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n struct AccountInfoCacheEntry {\n let account: AccountInfo\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored var providerRefreshTasks: [UsageProvider: [ProviderRefreshTaskState]] = [:]\n @ObservationIgnored var providerRefreshTaskGeneration: UInt64 = 0\n @ObservationIgnored var providerRefreshWaiterGeneration: UInt64 = 0\n @ObservationIgnored var latestProviderRefreshGenerations: [UsageProvider: UInt64] = [:]\n @ObservationIgnored var providerRefreshCounts: [UsageProvider: Int] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored var accountInfoCache: [UsageProvider: AccountInfoCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var memoryPressureReliefTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var storageRefreshInFlightRequestKey: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshRequestKey: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored let accountInfoCacheTTL: TimeInterval = 30\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: self.freshCodexVisibleAccountsForSnapshotHydration())\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?,\n coalesceProviderRefreshesOverride: Bool? = nil) async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase = Self.refreshPhase(hasCompletedInitialRefresh: self.hasCompletedInitialRefresh)\n let openAIWebRefreshPhase = Self.openAIWebRefreshPhase(\n providerRefreshPhase: refreshPhase,\n startupConnectivityRetryAttempt: startupConnectivityRetryAttempt)\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask {\n await self.refreshProvider(\n provider,\n coalesceIfRefreshing: coalesceProviderRefreshesOverride ??\n (ProviderInteractionContext.current == .background))\n }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage,\n refreshPhase: openAIWebRefreshPhase)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": openAIWebRefreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.freshCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n if refreshPhase == .startup {\n self.scheduleMemoryPressureRelief()\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n self.scheduleMemoryPressureRelief()\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.memoryPressureReliefTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n case antigravityQuotaSummary\n case antigravityLegacy\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n var source: SessionQuotaWindowSource?\n }\n\n func postQuotaWarning(_ event: QuotaWarningEvent, provider: UsageProvider) {\n self.sessionQuotaNotifier.postQuotaWarning(\n event: event,\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot, .devin,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "ca948292c16451cee9fca9d87e617c0e4ced0ee4": {"t": 1785757734.6175277, "n": 77629, "h": "d3acc59c8c2b9835", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.backgroundWorkSettingsObservationToken\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refreshForSettingsChange()\n }\n }\n }\n\n var backgroundWorkSettingsObservationToken: Int {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n return 0\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n struct AccountInfoCacheEntry {\n let account: AccountInfo\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored var providerRefreshTasks: [UsageProvider: [ProviderRefreshTaskState]] = [:]\n @ObservationIgnored var providerRefreshTaskGeneration: UInt64 = 0\n @ObservationIgnored var providerRefreshWaiterGeneration: UInt64 = 0\n @ObservationIgnored var latestProviderRefreshGenerations: [UsageProvider: UInt64] = [:]\n @ObservationIgnored var providerRefreshCounts: [UsageProvider: Int] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored var accountInfoCache: [UsageProvider: AccountInfoCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var memoryPressureReliefTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var storageRefreshInFlightRequestKey: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshRequestKey: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored let accountInfoCacheTTL: TimeInterval = 30\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: self.freshCodexVisibleAccountsForSnapshotHydration())\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?,\n coalesceProviderRefreshesOverride: Bool? = nil) async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase = Self.refreshPhase(hasCompletedInitialRefresh: self.hasCompletedInitialRefresh)\n let openAIWebRefreshPhase = Self.openAIWebRefreshPhase(\n providerRefreshPhase: refreshPhase,\n startupConnectivityRetryAttempt: startupConnectivityRetryAttempt)\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask {\n await self.refreshProvider(\n provider,\n coalesceIfRefreshing: coalesceProviderRefreshesOverride ??\n (ProviderInteractionContext.current == .background))\n }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage,\n refreshPhase: openAIWebRefreshPhase)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": openAIWebRefreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.freshCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n if refreshPhase == .startup {\n self.scheduleMemoryPressureRelief()\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n self.scheduleMemoryPressureRelief()\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.memoryPressureReliefTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n let primaryWindow = provider == .mimo ? nil : snapshot.primary\n let secondaryWindow = provider == .mimo ? nil : snapshot.secondary\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: primaryWindow,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: secondaryWindow,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot, .devin,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "be4818c68c1af34d6e56428d889f7754374c0f40": {"t": 1785757736.307714, "n": 78127, "h": "0482d3dd861d4a11", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.backgroundWorkSettingsObservationToken\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refreshForSettingsChange()\n }\n }\n }\n\n var backgroundWorkSettingsObservationToken: Int {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n return 0\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n struct AccountInfoCacheEntry {\n let account: AccountInfo\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored var providerRefreshTasks: [UsageProvider: [ProviderRefreshTaskState]] = [:]\n @ObservationIgnored var providerRefreshTaskGeneration: UInt64 = 0\n @ObservationIgnored var providerRefreshWaiterGeneration: UInt64 = 0\n @ObservationIgnored var latestProviderRefreshGenerations: [UsageProvider: UInt64] = [:]\n @ObservationIgnored var providerRefreshCounts: [UsageProvider: Int] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored var accountInfoCache: [UsageProvider: AccountInfoCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var memoryPressureReliefTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var storageRefreshInFlightRequestKey: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshRequestKey: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored let accountInfoCacheTTL: TimeInterval = 30\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: self.freshCodexVisibleAccountsForSnapshotHydration())\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?,\n coalesceProviderRefreshesOverride: Bool? = nil) async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase = Self.refreshPhase(hasCompletedInitialRefresh: self.hasCompletedInitialRefresh)\n let openAIWebRefreshPhase = Self.openAIWebRefreshPhase(\n providerRefreshPhase: refreshPhase,\n startupConnectivityRetryAttempt: startupConnectivityRetryAttempt)\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask {\n await self.refreshProvider(\n provider,\n coalesceIfRefreshing: coalesceProviderRefreshesOverride ??\n (ProviderInteractionContext.current == .background))\n }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage,\n refreshPhase: openAIWebRefreshPhase)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": openAIWebRefreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.freshCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n if refreshPhase == .startup {\n self.scheduleMemoryPressureRelief()\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n self.scheduleMemoryPressureRelief()\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.memoryPressureReliefTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot, .devin,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "3c2d53de57c118149b8511abb333aebb01cdf327": {"t": 1785757738.0782087, "n": 78119, "h": "dc8cab030eff7aa0", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.backgroundWorkSettingsObservationToken\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refreshForSettingsChange()\n }\n }\n }\n\n var backgroundWorkSettingsObservationToken: Int {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n return 0\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n struct AccountInfoCacheEntry {\n let account: AccountInfo\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored var providerRefreshTasks: [UsageProvider: [ProviderRefreshTaskState]] = [:]\n @ObservationIgnored var providerRefreshTaskGeneration: UInt64 = 0\n @ObservationIgnored var providerRefreshWaiterGeneration: UInt64 = 0\n @ObservationIgnored var latestProviderRefreshGenerations: [UsageProvider: UInt64] = [:]\n @ObservationIgnored var providerRefreshCounts: [UsageProvider: Int] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored var accountInfoCache: [UsageProvider: AccountInfoCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var memoryPressureReliefTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var storageRefreshInFlightRequestKey: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshRequestKey: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored let accountInfoCacheTTL: TimeInterval = 30\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: self.freshCodexVisibleAccountsForSnapshotHydration())\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?,\n coalesceProviderRefreshesOverride: Bool? = nil) async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase = Self.refreshPhase(hasCompletedInitialRefresh: self.hasCompletedInitialRefresh)\n let openAIWebRefreshPhase = Self.openAIWebRefreshPhase(\n providerRefreshPhase: refreshPhase,\n startupConnectivityRetryAttempt: startupConnectivityRetryAttempt)\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask {\n await self.refreshProvider(\n provider,\n coalesceIfRefreshing: coalesceProviderRefreshesOverride ??\n (ProviderInteractionContext.current == .background))\n }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage,\n refreshPhase: openAIWebRefreshPhase)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": openAIWebRefreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.freshCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n if refreshPhase == .startup {\n self.scheduleMemoryPressureRelief()\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n self.scheduleMemoryPressureRelief()\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.memoryPressureReliefTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "9778128bcb9c75778fd7ec6f4063e61ac1a992dd": {"t": 1785757739.9333704, "n": 77397, "h": "99e0cea35608008b", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.backgroundWorkSettingsObservationToken\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var backgroundWorkSettingsObservationToken: Int {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n return 0\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n struct AccountInfoCacheEntry {\n let account: AccountInfo\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored var accountInfoCache: [UsageProvider: AccountInfoCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var memoryPressureReliefTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var storageRefreshInFlightRequestKey: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshRequestKey: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored let accountInfoCacheTTL: TimeInterval = 30\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: self.freshCodexVisibleAccountsForSnapshotHydration())\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?)\n async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase = Self.refreshPhase(hasCompletedInitialRefresh: self.hasCompletedInitialRefresh)\n let openAIWebRefreshPhase = Self.openAIWebRefreshPhase(\n providerRefreshPhase: refreshPhase,\n startupConnectivityRetryAttempt: startupConnectivityRetryAttempt)\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage,\n refreshPhase: openAIWebRefreshPhase)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": openAIWebRefreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.freshCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n if refreshPhase == .startup {\n self.scheduleMemoryPressureRelief()\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n self.scheduleMemoryPressureRelief()\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.memoryPressureReliefTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "463ec9148768487b98d2502385f21a5096936a4c": {"t": 1785757741.6057413, "n": 77261, "h": "3c710cf61287e892", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.backgroundWorkSettingsObservationToken\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var backgroundWorkSettingsObservationToken: Int {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n return 0\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n struct AccountInfoCacheEntry {\n let account: AccountInfo\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored var accountInfoCache: [UsageProvider: AccountInfoCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var memoryPressureReliefTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored let accountInfoCacheTTL: TimeInterval = 30\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: self.freshCodexVisibleAccountsForSnapshotHydration())\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?)\n async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase = Self.refreshPhase(hasCompletedInitialRefresh: self.hasCompletedInitialRefresh)\n let openAIWebRefreshPhase = Self.openAIWebRefreshPhase(\n providerRefreshPhase: refreshPhase,\n startupConnectivityRetryAttempt: startupConnectivityRetryAttempt)\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage,\n refreshPhase: openAIWebRefreshPhase)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": openAIWebRefreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.freshCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n if refreshPhase == .startup {\n self.scheduleMemoryPressureRelief()\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n self.scheduleMemoryPressureRelief()\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.memoryPressureReliefTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "034300c8777bcf9d13e15b0cc1d5c78cc5bda8a9": {"t": 1785757743.3770938, "n": 77266, "h": "5730f8bac7d022b5", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.selectedMenuProvider\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n struct AccountInfoCacheEntry {\n let account: AccountInfo\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored var accountInfoCache: [UsageProvider: AccountInfoCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var memoryPressureReliefTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored let accountInfoCacheTTL: TimeInterval = 30\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: self.freshCodexVisibleAccountsForSnapshotHydration())\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?)\n async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase = Self.refreshPhase(hasCompletedInitialRefresh: self.hasCompletedInitialRefresh)\n let openAIWebRefreshPhase = Self.openAIWebRefreshPhase(\n providerRefreshPhase: refreshPhase,\n startupConnectivityRetryAttempt: startupConnectivityRetryAttempt)\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage,\n refreshPhase: openAIWebRefreshPhase)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": openAIWebRefreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.freshCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n if refreshPhase == .startup {\n self.scheduleMemoryPressureRelief()\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n self.scheduleMemoryPressureRelief()\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.memoryPressureReliefTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "3dcb72891fdff4e7ab2af57ce55ae2d35567b5a5": {"t": 1785757744.982157, "n": 77268, "h": "93df34641987ec2c", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.selectedMenuProvider\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n struct AccountInfoCacheEntry {\n let account: AccountInfo\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored var accountInfoCache: [UsageProvider: AccountInfoCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var memoryPressureReliefTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored let accountInfoCacheTTL: TimeInterval = 30\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: settings.codexVisibleAccountProjection.visibleAccounts)\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?)\n async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase = Self.refreshPhase(hasCompletedInitialRefresh: self.hasCompletedInitialRefresh)\n let openAIWebRefreshPhase = Self.openAIWebRefreshPhase(\n providerRefreshPhase: refreshPhase,\n startupConnectivityRetryAttempt: startupConnectivityRetryAttempt)\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage,\n refreshPhase: openAIWebRefreshPhase)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": openAIWebRefreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.freshCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n if refreshPhase == .startup {\n self.scheduleMemoryPressureRelief()\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n self.scheduleMemoryPressureRelief()\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.memoryPressureReliefTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "c7f8336e1314c25ed17ddb39f4bc9b5c34c74566": {"t": 1785757746.6307285, "n": 77270, "h": "21bac3f383204eec", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.selectedMenuProvider\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n struct AccountInfoCacheEntry {\n let account: AccountInfo\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored var accountInfoCache: [UsageProvider: AccountInfoCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var memoryPressureReliefTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored let accountInfoCacheTTL: TimeInterval = 30\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: settings.codexVisibleAccountProjection.visibleAccounts)\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?)\n async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase = Self.refreshPhase(hasCompletedInitialRefresh: self.hasCompletedInitialRefresh)\n let openAIWebRefreshPhase = Self.openAIWebRefreshPhase(\n providerRefreshPhase: refreshPhase,\n startupConnectivityRetryAttempt: startupConnectivityRetryAttempt)\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage,\n refreshPhase: openAIWebRefreshPhase)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": openAIWebRefreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.currentCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n if refreshPhase == .startup {\n self.scheduleMemoryPressureRelief()\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n self.scheduleMemoryPressureRelief()\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.memoryPressureReliefTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "917fc7229f10ec587e2430a557bb1b0675ba25c0": {"t": 1785757748.2552464, "n": 76829, "h": "7fba27ad675911d6", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.selectedMenuProvider\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var memoryPressureReliefTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: settings.codexVisibleAccountProjection.visibleAccounts)\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?)\n async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase = Self.refreshPhase(hasCompletedInitialRefresh: self.hasCompletedInitialRefresh)\n let openAIWebRefreshPhase = Self.openAIWebRefreshPhase(\n providerRefreshPhase: refreshPhase,\n startupConnectivityRetryAttempt: startupConnectivityRetryAttempt)\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage,\n refreshPhase: openAIWebRefreshPhase)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": openAIWebRefreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.currentCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n if refreshPhase == .startup {\n self.scheduleMemoryPressureRelief()\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n self.scheduleMemoryPressureRelief()\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.memoryPressureReliefTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "0dc51f9f43c5db33b30621974f9526ab75b6617c": {"t": 1785757750.12979, "n": 77014, "h": "32f114d1807ba571", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.selectedMenuProvider\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var memoryPressureReliefTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: settings.codexVisibleAccountProjection.visibleAccounts)\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?)\n async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase = Self.refreshPhase(hasCompletedInitialRefresh: self.hasCompletedInitialRefresh)\n let openAIWebRefreshPhase = Self.openAIWebRefreshPhase(\n providerRefreshPhase: refreshPhase,\n startupConnectivityRetryAttempt: startupConnectivityRetryAttempt)\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage,\n refreshPhase: openAIWebRefreshPhase)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": openAIWebRefreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.currentCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n if refreshPhase == .startup {\n self.scheduleMemoryPressureRelief()\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n self.scheduleMemoryPressureRelief()\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.memoryPressureReliefTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays,\n automaticCodexScanByteLimit: provider == .codex && !force\n ? Self.automaticCodexTokenScanByteLimit\n : nil)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "07ed3facdd4eea40d24e0aef56ffef94e3fb57ee": {"t": 1785757752.0843701, "n": 77851, "h": "2f8fdcfc8c98ad5e", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.selectedMenuProvider\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var memoryPressureReliefTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: settings.codexVisibleAccountProjection.visibleAccounts)\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?)\n async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase = Self.refreshPhase(hasCompletedInitialRefresh: self.hasCompletedInitialRefresh)\n let openAIWebRefreshPhase = Self.openAIWebRefreshPhase(\n providerRefreshPhase: refreshPhase,\n startupConnectivityRetryAttempt: startupConnectivityRetryAttempt)\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage,\n refreshPhase: openAIWebRefreshPhase)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": openAIWebRefreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.currentCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n if refreshPhase == .startup {\n self.scheduleMemoryPressureRelief()\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n self.scheduleMemoryPressureRelief()\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.memoryPressureReliefTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n func clearCostUsageCache() async -> String? {\n let errorMessage: String? = await Task.detached(priority: .utility) {\n let fm = FileManager.default\n let cacheDirs = [\n Self.costUsageCacheDirectory(fileManager: fm),\n ]\n\n for cacheDir in cacheDirs {\n do {\n try fm.removeItem(at: cacheDir)\n } catch let error as NSError {\n if error.domain == NSCocoaErrorDomain, error.code == NSFileNoSuchFileError { continue }\n return error.localizedDescription\n }\n }\n return nil\n }.value\n\n guard errorMessage == nil else { return errorMessage }\n\n self.tokenSnapshots.removeAll()\n self.tokenErrors.removeAll()\n self.lastTokenFetchAt.removeAll()\n self.lastTokenFetchScope.removeAll()\n self.tokenFailureGates[.codex]?.reset()\n self.tokenFailureGates[.claude]?.reset()\n return nil\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "d7db9922b5fbd5999a31a1990d185fa59d9926c0": {"t": 1785757754.2251039, "n": 77335, "h": "87b196ac4c859ae7", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.openAIDashboardAttachmentRevision\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.planUtilizationHistoryRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.selectedMenuProvider\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var planUtilizationHistoryRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false {\n didSet {\n guard self.openAIDashboardAttachmentAuthorized != oldValue else { return }\n self.openAIDashboardAttachmentRevision &+= 1\n }\n }\n\n var openAIDashboardAttachmentRevision = 0\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: settings.codexVisibleAccountProjection.visibleAccounts)\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.hydrateCachedTokenSnapshots()\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?)\n async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase: ProviderRefreshPhase = self.hasCompletedInitialRefresh ? .regular : .startup\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": refreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.currentCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n func clearCostUsageCache() async -> String? {\n let errorMessage: String? = await Task.detached(priority: .utility) {\n let fm = FileManager.default\n let cacheDirs = [\n Self.costUsageCacheDirectory(fileManager: fm),\n ]\n\n for cacheDir in cacheDirs {\n do {\n try fm.removeItem(at: cacheDir)\n } catch let error as NSError {\n if error.domain == NSCocoaErrorDomain, error.code == NSFileNoSuchFileError { continue }\n return error.localizedDescription\n }\n }\n return nil\n }.value\n\n guard errorMessage == nil else { return errorMessage }\n\n self.tokenSnapshots.removeAll()\n self.tokenErrors.removeAll()\n self.lastTokenFetchAt.removeAll()\n self.lastTokenFetchScope.removeAll()\n self.tokenFailureGates[.codex]?.reset()\n self.tokenFailureGates[.claude]?.reset()\n return nil\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "5ce38b605ccaaa62393ae025104824cd951ec407": {"t": 1785757755.7852128, "n": 76927, "h": "b94ca0e00ee51254", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.selectedMenuProvider\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var _test_providerStatusFetchOverride: (@MainActor (\n UsageProvider) async throws -> ProviderStatus)?\n @ObservationIgnored var _test_startupConnectivityRetryScheduled: (@MainActor (Int, TimeInterval) -> Void)?\n @ObservationIgnored var _test_startupConnectivityRetrySleepOverride: (@MainActor (\n TimeInterval) async throws -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored private let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryTask: Task<Void, Never>?\n @ObservationIgnored var startupConnectivityRetryNeeded = false\n @ObservationIgnored var startupConnectivityRetryRefreshActive = false\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: settings.codexVisibleAccountProjection.visibleAccounts)\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n await self.runRefresh(forceTokenUsage: forceTokenUsage, startupConnectivityRetryAttempt: nil)\n }\n\n func runRefresh(\n forceTokenUsage: Bool = false,\n startupConnectivityRetryAttempt: Int?)\n async\n {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase: ProviderRefreshPhase = self.hasCompletedInitialRefresh ? .regular : .startup\n let allowsStartupConnectivityRetry = refreshPhase == .startup || startupConnectivityRetryAttempt != nil\n self.startupConnectivityRetryRefreshActive = allowsStartupConnectivityRetry\n self.startupConnectivityRetryNeeded = false\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n self.startupConnectivityRetryRefreshActive = false\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": refreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.currentCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n\n if allowsStartupConnectivityRetry {\n self.completeStartupConnectivityRetryPass(currentAttempt: startupConnectivityRetryAttempt ?? 0)\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.startupConnectivityRetryTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let override = self._test_providerStatusFetchOverride {\n status = try await override(provider)\n } else if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n self.recordStartupConnectivityRetryableFailure(error)\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n func clearCostUsageCache() async -> String? {\n let errorMessage: String? = await Task.detached(priority: .utility) {\n let fm = FileManager.default\n let cacheDirs = [\n Self.costUsageCacheDirectory(fileManager: fm),\n ]\n\n for cacheDir in cacheDirs {\n do {\n try fm.removeItem(at: cacheDir)\n } catch let error as NSError {\n if error.domain == NSCocoaErrorDomain, error.code == NSFileNoSuchFileError { continue }\n return error.localizedDescription\n }\n }\n return nil\n }.value\n\n guard errorMessage == nil else { return errorMessage }\n\n self.tokenSnapshots.removeAll()\n self.tokenErrors.removeAll()\n self.lastTokenFetchAt.removeAll()\n self.lastTokenFetchScope.removeAll()\n self.tokenFailureGates[.codex]?.reset()\n self.tokenFailureGates[.claude]?.reset()\n return nil\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "72716d9fd545b6a5cfefae7f9828929b3b9af6f6": {"t": 1785757757.5231185, "n": 75934, "h": "a07194543eda9ac1", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.selectedMenuProvider\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n enum StartupBehavior {\n case automatic\n case full\n case testing\n\n var automaticallyStartsBackgroundWork: Bool {\n switch self {\n case .automatic, .full:\n true\n case .testing:\n false\n }\n }\n\n func resolved(isRunningTests: Bool) -> StartupBehavior {\n switch self {\n case .automatic:\n isRunningTests ? .testing : .full\n case .full, .testing:\n self\n }\n }\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n Bool,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored private let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored private let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: settings.codexVisibleAccountProjection.visibleAccounts)\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase: ProviderRefreshPhase = self.hasCompletedInitialRefresh ? .regular : .startup\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": refreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.currentCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n func clearCostUsageCache() async -> String? {\n let errorMessage: String? = await Task.detached(priority: .utility) {\n let fm = FileManager.default\n let cacheDirs = [\n Self.costUsageCacheDirectory(fileManager: fm),\n ]\n\n for cacheDir in cacheDirs {\n do {\n try fm.removeItem(at: cacheDir)\n } catch let error as NSError {\n if error.domain == NSCocoaErrorDomain, error.code == NSFileNoSuchFileError { continue }\n return error.localizedDescription\n }\n }\n return nil\n }.value\n\n guard errorMessage == nil else { return errorMessage }\n\n self.tokenSnapshots.removeAll()\n self.tokenErrors.removeAll()\n self.lastTokenFetchAt.removeAll()\n self.lastTokenFetchScope.removeAll()\n self.tokenFailureGates[.codex]?.reset()\n self.tokenFailureGates[.claude]?.reset()\n return nil\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "8fccb454acbb31f141756c63988973a5ae8ca4df": {"t": 1785757759.0289185, "n": 75920, "h": "646423b40c0453a2", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.selectedMenuProvider\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n enum StartupBehavior {\n case automatic\n case full\n case testing\n\n var automaticallyStartsBackgroundWork: Bool {\n switch self {\n case .automatic, .full:\n true\n case .testing:\n false\n }\n }\n\n func resolved(isRunningTests: Bool) -> StartupBehavior {\n switch self {\n case .automatic:\n isRunningTests ? .testing : .full\n case .full, .testing:\n self\n }\n }\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored private let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored private let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: settings.codexVisibleAccountProjection.visibleAccounts)\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase: ProviderRefreshPhase = self.hasCompletedInitialRefresh ? .regular : .startup\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": refreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.currentCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n func clearCostUsageCache() async -> String? {\n let errorMessage: String? = await Task.detached(priority: .utility) {\n let fm = FileManager.default\n let cacheDirs = [\n Self.costUsageCacheDirectory(fileManager: fm),\n ]\n\n for cacheDir in cacheDirs {\n do {\n try fm.removeItem(at: cacheDir)\n } catch let error as NSError {\n if error.domain == NSCocoaErrorDomain, error.code == NSFileNoSuchFileError { continue }\n return error.localizedDescription\n }\n }\n return nil\n }.value\n\n guard errorMessage == nil else { return errorMessage }\n\n self.tokenSnapshots.removeAll()\n self.tokenErrors.removeAll()\n self.lastTokenFetchAt.removeAll()\n self.lastTokenFetchScope.removeAll()\n self.tokenFailureGates[.codex]?.reset()\n self.tokenFailureGates[.claude]?.reset()\n return nil\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n if Self.tokenCostRequiresProviderSnapshot(provider) {\n if let snapshot = self.tokenSnapshot(fromProviderSnapshot: self.snapshots[provider], provider: provider) {\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n }\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // Codex cost usage scans local session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget that fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD\n .map { UsageFormatter.currencyString($0, currencyCode: snapshot.currencyCode) } ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "c2b63a01bae4f709d7c57fd874895ab297cc20ed": {"t": 1785757760.7531543, "n": 75147, "h": "45253836d4f41870", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.selectedMenuProvider\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n enum StartupBehavior {\n case automatic\n case full\n case testing\n\n var automaticallyStartsBackgroundWork: Bool {\n switch self {\n case .automatic, .full:\n true\n case .testing:\n false\n }\n }\n\n func resolved(isRunningTests: Bool) -> StartupBehavior {\n switch self {\n case .automatic:\n isRunningTests ? .testing : .full\n case .full, .testing:\n self\n }\n }\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var creditsRefreshTask: Task<Void, Never>?\n @ObservationIgnored var creditsRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardBackgroundRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored private let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored private let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: settings.codexVisibleAccountProjection.visibleAccounts)\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase: ProviderRefreshPhase = self.hasCompletedInitialRefresh ? .regular : .startup\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n if forceTokenUsage {\n group.addTask { await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n }\n\n if !forceTokenUsage {\n self.scheduleCreditsRefreshIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": refreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.currentCodexOpenAIWebRefreshGuard()\n if forceTokenUsage {\n await self.refreshOpenAIDashboardIfNeeded(\n force: true,\n expectedGuard: codexDashboardGuard)\n } else {\n self.scheduleOpenAIDashboardRefreshIfNeeded(expectedGuard: codexDashboardGuard)\n }\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n func clearCostUsageCache() async -> String? {\n let errorMessage: String? = await Task.detached(priority: .utility) {\n let fm = FileManager.default\n let cacheDirs = [\n Self.costUsageCacheDirectory(fileManager: fm),\n ]\n\n for cacheDir in cacheDirs {\n do {\n try fm.removeItem(at: cacheDir)\n } catch let error as NSError {\n if error.domain == NSCocoaErrorDomain, error.code == NSFileNoSuchFileError { continue }\n return error.localizedDescription\n }\n }\n return nil\n }.value\n\n guard errorMessage == nil else { return errorMessage }\n\n self.tokenSnapshots.removeAll()\n self.tokenErrors.removeAll()\n self.lastTokenFetchAt.removeAll()\n self.lastTokenFetchScope.removeAll()\n self.tokenFailureGates[.codex]?.reset()\n self.tokenFailureGates[.claude]?.reset()\n return nil\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard provider == .codex || provider == .claude || provider == .vertexai || provider == .bedrock else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // CostUsageFetcher scans local Codex session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget this fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD.map(UsageFormatter.usdString) ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD.map(UsageFormatter.usdString) ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "b2bc921ab8b88498a3a1a041eb822b7142cd0ab9": {"t": 1785757762.466366, "n": 74484, "h": "129dc1da2decd118", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.selectedMenuProvider\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n enum StartupBehavior {\n case automatic\n case full\n case testing\n\n var automaticallyStartsBackgroundWork: Bool {\n switch self {\n case .automatic, .full:\n true\n case .testing:\n false\n }\n }\n\n func resolved(isRunningTests: Bool) -> StartupBehavior {\n switch self {\n case .automatic:\n isRunningTests ? .testing : .full\n case .full, .testing:\n self\n }\n }\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored private let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored private let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: settings.codexVisibleAccountProjection.visibleAccounts)\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase: ProviderRefreshPhase = self.hasCompletedInitialRefresh ? .regular : .startup\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n group.addTask { await self.refreshCreditsIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": refreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.currentCodexOpenAIWebRefreshGuard()\n await self.refreshOpenAIDashboardIfNeeded(\n force: forceTokenUsage,\n expectedGuard: codexDashboardGuard)\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n // swiftlint:disable:next function_body_length\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .alibabatokenplan: \"Alibaba Token Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .alibabatokenplan, .factory, .copilot,\n .vertexai, .kilo, .kiro, .kimi, .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao,\n .abacus, .mistral, .codebuff, .crof, .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock,\n .grok, .groq, .t3chat, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n func clearCostUsageCache() async -> String? {\n let errorMessage: String? = await Task.detached(priority: .utility) {\n let fm = FileManager.default\n let cacheDirs = [\n Self.costUsageCacheDirectory(fileManager: fm),\n ]\n\n for cacheDir in cacheDirs {\n do {\n try fm.removeItem(at: cacheDir)\n } catch let error as NSError {\n if error.domain == NSCocoaErrorDomain, error.code == NSFileNoSuchFileError { continue }\n return error.localizedDescription\n }\n }\n return nil\n }.value\n\n guard errorMessage == nil else { return errorMessage }\n\n self.tokenSnapshots.removeAll()\n self.tokenErrors.removeAll()\n self.lastTokenFetchAt.removeAll()\n self.lastTokenFetchScope.removeAll()\n self.tokenFailureGates[.codex]?.reset()\n self.tokenFailureGates[.claude]?.reset()\n return nil\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard provider == .codex || provider == .claude || provider == .vertexai || provider == .bedrock else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // CostUsageFetcher scans local Codex session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget this fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD.map(UsageFormatter.usdString) ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD.map(UsageFormatter.usdString) ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "4bf5ccbd945092c59b5f2d71f7d4885ed286880f": {"t": 1785757763.9936335, "n": 74327, "h": "6e5bc899ab9c7ee9", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.selectedMenuProvider\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n enum StartupBehavior {\n case automatic\n case full\n case testing\n\n var automaticallyStartsBackgroundWork: Bool {\n switch self {\n case .automatic, .full:\n true\n case .testing:\n false\n }\n }\n\n func resolved(isRunningTests: Bool) -> StartupBehavior {\n switch self {\n case .automatic:\n isRunningTests ? .testing : .full\n case .full, .testing:\n self\n }\n }\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored private let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored private let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: settings.codexVisibleAccountProjection.visibleAccounts)\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase: ProviderRefreshPhase = self.hasCompletedInitialRefresh ? .regular : .startup\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n group.addTask { await self.refreshCreditsIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": refreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.currentCodexOpenAIWebRefreshGuard()\n await self.refreshOpenAIDashboardIfNeeded(\n force: forceTokenUsage,\n expectedGuard: codexDashboardGuard)\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .t3chat: \"T3 Chat debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .factory, .copilot, .vertexai, .kilo, .kiro, .kimi,\n .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao, .abacus, .mistral, .codebuff, .crof,\n .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock, .grok, .groq, .t3chat, .llmproxy,\n .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n func clearCostUsageCache() async -> String? {\n let errorMessage: String? = await Task.detached(priority: .utility) {\n let fm = FileManager.default\n let cacheDirs = [\n Self.costUsageCacheDirectory(fileManager: fm),\n ]\n\n for cacheDir in cacheDirs {\n do {\n try fm.removeItem(at: cacheDir)\n } catch let error as NSError {\n if error.domain == NSCocoaErrorDomain, error.code == NSFileNoSuchFileError { continue }\n return error.localizedDescription\n }\n }\n return nil\n }.value\n\n guard errorMessage == nil else { return errorMessage }\n\n self.tokenSnapshots.removeAll()\n self.tokenErrors.removeAll()\n self.lastTokenFetchAt.removeAll()\n self.lastTokenFetchScope.removeAll()\n self.tokenFailureGates[.codex]?.reset()\n self.tokenFailureGates[.claude]?.reset()\n return nil\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard provider == .codex || provider == .claude || provider == .vertexai || provider == .bedrock else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // CostUsageFetcher scans local Codex session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget this fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD.map(UsageFormatter.usdString) ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD.map(UsageFormatter.usdString) ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "d5bf26974b85ff04e974f7c717d550681cc0ea40": {"t": 1785757765.630227, "n": 74231, "h": "a81ad3c92c95760e", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.selectedMenuProvider\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n enum StartupBehavior {\n case automatic\n case full\n case testing\n\n var automaticallyStartsBackgroundWork: Bool {\n switch self {\n case .automatic, .full:\n true\n case .testing:\n false\n }\n }\n\n func resolved(isRunningTests: Bool) -> StartupBehavior {\n switch self {\n case .automatic:\n isRunningTests ? .testing : .full\n case .full, .testing:\n self\n }\n }\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored private let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored private let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: settings.codexVisibleAccountProjection.visibleAccounts)\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase: ProviderRefreshPhase = self.hasCompletedInitialRefresh ? .regular : .startup\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n group.addTask { await self.refreshCreditsIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": refreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.currentCodexOpenAIWebRefreshGuard()\n await self.refreshOpenAIDashboardIfNeeded(\n force: forceTokenUsage,\n expectedGuard: codexDashboardGuard)\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .factory, .copilot, .vertexai, .kilo, .kiro, .kimi,\n .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao, .abacus, .mistral, .codebuff, .crof,\n .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock, .grok, .groq, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n func clearCostUsageCache() async -> String? {\n let errorMessage: String? = await Task.detached(priority: .utility) {\n let fm = FileManager.default\n let cacheDirs = [\n Self.costUsageCacheDirectory(fileManager: fm),\n ]\n\n for cacheDir in cacheDirs {\n do {\n try fm.removeItem(at: cacheDir)\n } catch let error as NSError {\n if error.domain == NSCocoaErrorDomain, error.code == NSFileNoSuchFileError { continue }\n return error.localizedDescription\n }\n }\n return nil\n }.value\n\n guard errorMessage == nil else { return errorMessage }\n\n self.tokenSnapshots.removeAll()\n self.tokenErrors.removeAll()\n self.lastTokenFetchAt.removeAll()\n self.lastTokenFetchScope.removeAll()\n self.tokenFailureGates[.codex]?.reset()\n self.tokenFailureGates[.claude]?.reset()\n return nil\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard provider == .codex || provider == .claude || provider == .vertexai || provider == .bedrock else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // CostUsageFetcher scans local Codex session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget this fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD.map(UsageFormatter.usdString) ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD.map(UsageFormatter.usdString) ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "daaa271c27e675fc5a47c75e66cf3a9176db89ce": {"t": 1785757767.2205007, "n": 74261, "h": "41099161d88cded5", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.selectedMenuProvider\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n enum StartupBehavior {\n case automatic\n case full\n case testing\n\n var automaticallyStartsBackgroundWork: Bool {\n switch self {\n case .automatic, .full:\n true\n case .testing:\n false\n }\n }\n\n func resolved(isRunningTests: Bool) -> StartupBehavior {\n switch self {\n case .automatic:\n isRunningTests ? .testing : .full\n case .full, .testing:\n self\n }\n }\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored private let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored private let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: settings.codexVisibleAccountProjection.visibleAccounts)\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase: ProviderRefreshPhase = self.hasCompletedInitialRefresh ? .regular : .startup\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n group.addTask { await self.refreshCreditsIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": refreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.currentCodexOpenAIWebRefreshGuard()\n await self.refreshOpenAIDashboardIfNeeded(\n force: forceTokenUsage,\n expectedGuard: codexDashboardGuard)\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let azureOpenAIDebugContext = self.azureOpenAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .azureopenai:\n return Self.apiKeyDebugLine(azureOpenAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .factory, .copilot, .vertexai, .kilo, .kiro, .kimi,\n .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao, .abacus, .mistral, .codebuff, .crof,\n .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock, .grok, .groq, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func azureOpenAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .azureopenai)\n let environment = ProviderConfigEnvironment.applyProviderConfigOverrides(\n base: processEnvironment,\n provider: .azureopenai,\n config: config)\n return APIKeyDebugContext(\n label: \"AZURE_OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.azureOpenAIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: AzureOpenAISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n func clearCostUsageCache() async -> String? {\n let errorMessage: String? = await Task.detached(priority: .utility) {\n let fm = FileManager.default\n let cacheDirs = [\n Self.costUsageCacheDirectory(fileManager: fm),\n ]\n\n for cacheDir in cacheDirs {\n do {\n try fm.removeItem(at: cacheDir)\n } catch let error as NSError {\n if error.domain == NSCocoaErrorDomain, error.code == NSFileNoSuchFileError { continue }\n return error.localizedDescription\n }\n }\n return nil\n }.value\n\n guard errorMessage == nil else { return errorMessage }\n\n self.tokenSnapshots.removeAll()\n self.tokenErrors.removeAll()\n self.lastTokenFetchAt.removeAll()\n self.lastTokenFetchScope.removeAll()\n self.tokenFailureGates[.codex]?.reset()\n self.tokenFailureGates[.claude]?.reset()\n return nil\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard provider == .codex || provider == .claude || provider == .vertexai || provider == .bedrock else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // CostUsageFetcher scans local Codex session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget this fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD.map(UsageFormatter.usdString) ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD.map(UsageFormatter.usdString) ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "bdba75fb0cb8909f789038c7c393bb823658b3b1": {"t": 1785757769.2005901, "n": 73313, "h": "6d17cdb2dc82bf46", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.selectedMenuProvider\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n enum StartupBehavior {\n case automatic\n case full\n case testing\n\n var automaticallyStartsBackgroundWork: Bool {\n switch self {\n case .automatic, .full:\n true\n case .testing:\n false\n }\n }\n\n func resolved(isRunningTests: Bool) -> StartupBehavior {\n switch self {\n case .automatic:\n isRunningTests ? .testing : .full\n case .full, .testing:\n self\n }\n }\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var _test_providerRefreshOverride: (@MainActor (UsageProvider) async -> Void)?\n @ObservationIgnored var _test_tokenUsageRefreshOverride: (@MainActor (UsageProvider, Bool) async -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored private let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored private let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: settings.codexVisibleAccountProjection.visibleAccounts)\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase: ProviderRefreshPhase = self.hasCompletedInitialRefresh ? .regular : .startup\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n group.addTask { await self.refreshCreditsIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n\n if forceTokenUsage {\n await self.refreshTokenUsageSequenceNow(force: true)\n } else {\n // Token-cost usage can be slow; run it outside regular/menu-open refreshes so we don't block UI.\n self.scheduleTokenRefresh(force: false)\n }\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": refreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.currentCodexOpenAIWebRefreshGuard()\n await self.refreshOpenAIDashboardIfNeeded(\n force: forceTokenUsage,\n expectedGuard: codexDashboardGuard)\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n await self.refreshTokenUsageSequence(force: force)\n }\n }\n\n private func refreshTokenUsageSequenceNow(force: Bool) async {\n if force, let existing = self.tokenRefreshSequenceTask {\n existing.cancel()\n await existing.value\n self.tokenRefreshSequenceTask = nil\n }\n\n await self.refreshTokenUsageSequence(force: force)\n }\n\n private func refreshTokenUsageSequence(force: Bool) async {\n for provider in self.enabledProvidersForBackgroundWork() {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .factory, .copilot, .vertexai, .kilo, .kiro, .kimi,\n .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao, .abacus, .mistral, .codebuff, .crof,\n .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock, .grok, .groq, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n func clearCostUsageCache() async -> String? {\n let errorMessage: String? = await Task.detached(priority: .utility) {\n let fm = FileManager.default\n let cacheDirs = [\n Self.costUsageCacheDirectory(fileManager: fm),\n ]\n\n for cacheDir in cacheDirs {\n do {\n try fm.removeItem(at: cacheDir)\n } catch let error as NSError {\n if error.domain == NSCocoaErrorDomain, error.code == NSFileNoSuchFileError { continue }\n return error.localizedDescription\n }\n }\n return nil\n }.value\n\n guard errorMessage == nil else { return errorMessage }\n\n self.tokenSnapshots.removeAll()\n self.tokenErrors.removeAll()\n self.lastTokenFetchAt.removeAll()\n self.lastTokenFetchScope.removeAll()\n self.tokenFailureGates[.codex]?.reset()\n self.tokenFailureGates[.claude]?.reset()\n return nil\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard provider == .codex || provider == .claude || provider == .vertexai || provider == .bedrock else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n if let override = self._test_tokenUsageRefreshOverride {\n await override(provider, force)\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // CostUsageFetcher scans local Codex session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget this fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD.map(UsageFormatter.usdString) ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD.map(UsageFormatter.usdString) ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "d715648cf23d8b95bd6b3a7c7509e82a21493f1f": {"t": 1785757770.852434, "n": 72421, "h": "aacb104c002a9ff4", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.costUsageHistoryDays\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.selectedMenuProvider\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n enum StartupBehavior {\n case automatic\n case full\n case testing\n\n var automaticallyStartsBackgroundWork: Bool {\n switch self {\n case .automatic, .full:\n true\n case .testing:\n false\n }\n }\n\n func resolved(isRunningTests: Bool) -> StartupBehavior {\n switch self {\n case .automatic:\n isRunningTests ? .testing : .full\n case .full, .testing:\n self\n }\n }\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored private let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastPermissionPromptNotificationAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored private let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: settings.codexVisibleAccountProjection.visibleAccounts)\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase: ProviderRefreshPhase = self.hasCompletedInitialRefresh ? .regular : .startup\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n group.addTask { await self.refreshCreditsIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n\n // Token-cost usage can be slow; run it outside the refresh group so we don't block menu updates.\n self.scheduleTokenRefresh(force: forceTokenUsage)\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": refreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.currentCodexOpenAIWebRefreshGuard()\n await self.refreshOpenAIDashboardIfNeeded(\n force: forceTokenUsage,\n expectedGuard: codexDashboardGuard)\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n let providers = self.enabledProvidersForBackgroundWork()\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n for provider in providers {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n }\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .groq: \"Groq debug log not yet implemented\",\n .llmproxy: \"LLM Proxy debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .factory, .copilot, .vertexai, .kilo, .kiro, .kimi,\n .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao, .abacus, .mistral, .codebuff, .crof,\n .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock, .grok, .groq, .llmproxy, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n func clearCostUsageCache() async -> String? {\n let errorMessage: String? = await Task.detached(priority: .utility) {\n let fm = FileManager.default\n let cacheDirs = [\n Self.costUsageCacheDirectory(fileManager: fm),\n ]\n\n for cacheDir in cacheDirs {\n do {\n try fm.removeItem(at: cacheDir)\n } catch let error as NSError {\n if error.domain == NSCocoaErrorDomain, error.code == NSFileNoSuchFileError { continue }\n return error.localizedDescription\n }\n }\n return nil\n }.value\n\n guard errorMessage == nil else { return errorMessage }\n\n self.tokenSnapshots.removeAll()\n self.tokenErrors.removeAll()\n self.lastTokenFetchAt.removeAll()\n self.lastTokenFetchScope.removeAll()\n self.tokenFailureGates[.codex]?.reset()\n self.tokenFailureGates[.claude]?.reset()\n return nil\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard provider == .codex || provider == .claude || provider == .vertexai || provider == .bedrock else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let historyDays = self.settings.costUsageHistoryDays\n let costScope = self.tokenCostScope(for: provider)\n let costScopeSignature = \"\\(costScope.signature)|historyDays=\\(historyDays)\"\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScopeSignature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScopeSignature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // CostUsageFetcher scans local Codex session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget this fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath,\n historyDays: historyDays)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD.map(UsageFormatter.usdString) ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD.map(UsageFormatter.usdString) ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"historyDays=\\(historyDays) windowCost=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}, "eed34a7bc00deb72c75876ffec0445193b4640bc": {"t": 1785757772.7202156, "n": 71901, "h": "7e6f82e7bc1aaa56", "c": "import AppKit\nimport CodexBarCore\nimport Foundation\nimport Observation\nimport SweetCookieKit\n\n// MARK: - Observation helpers\n\n@MainActor\nextension UsageStore {\n var menuObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.lastSourceLabels\n _ = self.lastFetchAttempts\n _ = self.accountSnapshots\n _ = self.codexAccountSnapshots\n _ = self.kiloScopeSnapshots\n _ = self.tokenSnapshots\n _ = self.tokenErrors\n _ = self.tokenRefreshInFlight\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.versions\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.pathDebugInfo\n _ = self.statuses\n _ = self.probeLogs\n _ = self.historicalPaceRevision\n _ = self.providerStorageFootprints\n return 0\n }\n\n var iconObservationToken: Int {\n _ = self.snapshots\n _ = self.errors\n _ = self.credits\n _ = self.lastCreditsError\n _ = self.openAIDashboard\n _ = self.lastOpenAIDashboardError\n _ = self.openAIDashboardRequiresLogin\n _ = self.isRefreshing\n _ = self.refreshingProviders\n _ = self.statuses\n _ = self.historicalPaceRevision\n return 0\n }\n\n func observeSettingsChanges() {\n withObservationTracking {\n _ = self.settings.refreshFrequency\n _ = self.settings.statusChecksEnabled\n _ = self.settings.sessionQuotaNotificationsEnabled\n _ = self.settings.quotaWarningNotificationsEnabled\n _ = self.settings.quotaWarningThresholds\n _ = self.settings.quotaWarningThresholds(.session)\n _ = self.settings.quotaWarningThresholds(.weekly)\n _ = self.settings.quotaWarningSoundEnabled\n _ = self.settings.usageBarsShowUsed\n _ = self.settings.costUsageEnabled\n _ = self.settings.randomBlinkEnabled\n _ = self.settings.configRevision\n for implementation in ProviderCatalog.all {\n implementation.observeSettings(self.settings)\n }\n _ = self.settings.multiAccountMenuLayout\n _ = self.settings.tokenAccountsByProvider\n _ = self.settings.mergeIcons\n _ = self.settings.selectedMenuProvider\n _ = self.settings.debugLoadingPattern\n _ = self.settings.debugKeepCLISessionsAlive\n _ = self.settings.historicalTrackingEnabled\n _ = self.settings.providerStorageFootprintsEnabled\n } onChange: { [weak self] in\n Task { @MainActor [weak self] in\n guard let self else { return }\n self.observeSettingsChanges()\n self.invalidateProviderAvailabilityCache()\n self.probeLogs = [:]\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.startTimer()\n self.updateProviderRuntimes()\n await self.refreshHistoricalDatasetIfNeeded()\n await self.refresh()\n }\n }\n }\n\n var attachedOpenAIDashboardSnapshot: OpenAIDashboardSnapshot? {\n guard self.openAIDashboardAttachmentAuthorized else { return nil }\n return self.openAIDashboard\n }\n}\n\n@MainActor\n@Observable\nfinal class UsageStore {\n private struct ProviderAvailabilityCacheEntry {\n let available: Bool\n let configRevision: Int\n let expiresAt: Date\n\n func isValid(now: Date, configRevision: Int) -> Bool {\n self.configRevision == configRevision && self.expiresAt > now\n }\n }\n\n enum CodexCreditsSource {\n case none\n case api\n case dashboardWeb\n }\n\n enum StartupBehavior {\n case automatic\n case full\n case testing\n\n var automaticallyStartsBackgroundWork: Bool {\n switch self {\n case .automatic, .full:\n true\n case .testing:\n false\n }\n }\n\n func resolved(isRunningTests: Bool) -> StartupBehavior {\n switch self {\n case .automatic:\n isRunningTests ? .testing : .full\n case .full, .testing:\n self\n }\n }\n }\n\n var snapshots: [UsageProvider: UsageSnapshot] = [:]\n var errors: [UsageProvider: String] = [:]\n var lastSourceLabels: [UsageProvider: String] = [:]\n var lastFetchAttempts: [UsageProvider: [ProviderFetchAttempt]] = [:]\n var accountSnapshots: [UsageProvider: [TokenAccountUsageSnapshot]] = [:]\n var codexAccountSnapshots: [CodexAccountUsageSnapshot] = []\n var kiloScopeSnapshots: [KiloScopeSnapshot] = []\n var tokenSnapshots: [UsageProvider: CostUsageTokenSnapshot] = [:]\n var tokenErrors: [UsageProvider: String] = [:]\n var tokenRefreshInFlight: Set<UsageProvider> = []\n var credits: CreditsSnapshot?\n var lastCreditsError: String?\n var openAIDashboard: OpenAIDashboardSnapshot?\n var lastOpenAIDashboardError: String?\n var openAIDashboardRequiresLogin: Bool = false\n var openAIDashboardCookieImportStatus: String?\n var openAIDashboardCookieImportDebugLog: String?\n var versions: [UsageProvider: String] = [:]\n var isRefreshing = false\n var refreshingProviders: Set<UsageProvider> = []\n var debugForceAnimation = false\n var pathDebugInfo: PathDebugSnapshot = .empty\n var statuses: [UsageProvider: ProviderStatus] = [:]\n var probeLogs: [UsageProvider: String] = [:]\n var historicalPaceRevision: Int = 0\n var providerStorageFootprints: [UsageProvider: ProviderStorageFootprint] = [:]\n @ObservationIgnored var lastCreditsSnapshot: CreditsSnapshot?\n @ObservationIgnored var lastCreditsSnapshotAccountKey: String?\n @ObservationIgnored var lastCreditsSource: CodexCreditsSource = .none\n @ObservationIgnored var creditsFailureStreak: Int = 0\n @ObservationIgnored var openAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardSnapshot: OpenAIDashboardSnapshot?\n @ObservationIgnored var lastOpenAIDashboardAttachmentAuthorized: Bool = false\n @ObservationIgnored var lastOpenAIDashboardTargetEmail: String?\n @ObservationIgnored var lastOpenAIDashboardAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportAttemptAt: Date?\n @ObservationIgnored var lastOpenAIDashboardCookieImportEmail: String?\n @ObservationIgnored var lastCodexAccountScopedRefreshGuard: CodexAccountScopedRefreshGuard?\n @ObservationIgnored var lastKnownLiveSystemCodexEmail: String?\n @ObservationIgnored var openAIWebAccountDidChange: Bool = false\n @ObservationIgnored var openAIDashboardRefreshTask: Task<Void, Never>?\n @ObservationIgnored var openAIDashboardRefreshTaskKey: String?\n @ObservationIgnored var openAIDashboardRefreshTaskToken: UUID?\n @ObservationIgnored var _test_openAIDashboardCookieImportOverride: (@MainActor (\n String?,\n Bool,\n ProviderCookieSource,\n CookieHeaderCache.Scope?,\n @escaping (String) -> Void) async throws -> OpenAIDashboardBrowserCookieImporter.ImportResult)?\n @ObservationIgnored var _test_openAIDashboardLoaderOverride: (@MainActor (\n String?,\n @escaping (String) -> Void,\n TimeInterval) async throws -> OpenAIDashboardSnapshot)?\n @ObservationIgnored var _test_codexCreditsLoaderOverride: (@MainActor () async throws -> CreditsSnapshot)?\n @ObservationIgnored var _test_widgetSnapshotSaveOverride: (@MainActor (WidgetSnapshot) async -> Void)?\n @ObservationIgnored var widgetSnapshotPersistTask: Task<Void, Never>?\n\n @ObservationIgnored let codexFetcher: UsageFetcher\n @ObservationIgnored let claudeFetcher: any ClaudeUsageFetching\n @ObservationIgnored private let costUsageFetcher: CostUsageFetcher\n @ObservationIgnored let browserDetection: BrowserDetection\n @ObservationIgnored private let registry: ProviderRegistry\n @ObservationIgnored let settings: SettingsStore\n @ObservationIgnored let environmentBase: [String: String]\n @ObservationIgnored private let sessionQuotaNotifier: any SessionQuotaNotifying\n @ObservationIgnored private let sessionQuotaLogger = CodexBarLog.logger(LogCategories.sessionQuota)\n @ObservationIgnored let openAIWebLogger = CodexBarLog.logger(LogCategories.openAIWeb)\n @ObservationIgnored private let tokenCostLogger = CodexBarLog.logger(LogCategories.tokenCost)\n @ObservationIgnored let augmentLogger = CodexBarLog.logger(LogCategories.augment)\n @ObservationIgnored let providerLogger = CodexBarLog.logger(LogCategories.providers)\n @ObservationIgnored var openAIWebDebugLines: [String] = []\n @ObservationIgnored var failureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var tokenFailureGates: [UsageProvider: ConsecutiveFailureGate] = [:]\n @ObservationIgnored var providerSpecs: [UsageProvider: ProviderSpec] = [:]\n @ObservationIgnored let providerMetadata: [UsageProvider: ProviderMetadata]\n @ObservationIgnored var providerRuntimes: [UsageProvider: any ProviderRuntime] = [:]\n @ObservationIgnored private var providerAvailabilityCache: [UsageProvider: ProviderAvailabilityCacheEntry] = [:]\n @ObservationIgnored private var timerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenTimerTask: Task<Void, Never>?\n @ObservationIgnored private var tokenRefreshSequenceTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshTask: Task<Void, Never>?\n @ObservationIgnored var storageRefreshGeneration: UInt64 = 0\n @ObservationIgnored var storageRefreshInFlightSignature: String?\n @ObservationIgnored var lastStorageRefreshSignature: String?\n @ObservationIgnored var lastStorageRefreshAt: Date?\n @ObservationIgnored var managedCodexAccountsForStorageOverride: [ManagedCodexAccount]?\n @ObservationIgnored private var pathDebugRefreshTask: Task<Void, Never>?\n @ObservationIgnored var codexPlanHistoryBackfillTask: Task<Void, Never>?\n @ObservationIgnored let historicalUsageHistoryStore: HistoricalUsageHistoryStore\n @ObservationIgnored let planUtilizationHistoryStore: PlanUtilizationHistoryStore\n @ObservationIgnored let codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)?\n @ObservationIgnored var codexHistoricalDataset: CodexHistoricalDataset?\n @ObservationIgnored var codexHistoricalDatasetAccountKey: String?\n @ObservationIgnored var lastKnownResetSnapshots: [UsageProvider: UsageSnapshot] = [:]\n @ObservationIgnored var lastKnownSessionRemaining: [UsageProvider: Double] = [:]\n @ObservationIgnored var lastKnownSessionWindowSource: [UsageProvider: SessionQuotaWindowSource] = [:]\n @ObservationIgnored var quotaWarningState: [QuotaWarningStateKey: QuotaWarningState] = [:]\n @ObservationIgnored var lastTokenFetchAt: [UsageProvider: Date] = [:]\n @ObservationIgnored var lastTokenFetchScope: [UsageProvider: String] = [:]\n @ObservationIgnored var planUtilizationHistory: [UsageProvider: PlanUtilizationHistoryBuckets] = [:]\n @ObservationIgnored var weeklyLimitResetDetectorStates: [String: WeeklyLimitResetDetectorState] = [:]\n @ObservationIgnored private var hasCompletedInitialRefresh: Bool = false\n @ObservationIgnored private let providerAvailabilityCacheTTL: TimeInterval = 1\n @ObservationIgnored private let tokenFetchTTL: TimeInterval = 60 * 60\n @ObservationIgnored private let tokenFetchTimeout: TimeInterval = 10 * 60\n @ObservationIgnored private let startupBehavior: StartupBehavior\n @ObservationIgnored let planUtilizationPersistenceCoordinator: PlanUtilizationHistoryPersistenceCoordinator\n\n init(\n fetcher: UsageFetcher,\n browserDetection: BrowserDetection,\n claudeFetcher: (any ClaudeUsageFetching)? = nil,\n costUsageFetcher: CostUsageFetcher = CostUsageFetcher(),\n settings: SettingsStore,\n registry: ProviderRegistry = .shared,\n historicalUsageHistoryStore: HistoricalUsageHistoryStore = HistoricalUsageHistoryStore(),\n planUtilizationHistoryStore: PlanUtilizationHistoryStore = .defaultAppSupport(),\n codexAccountUsageSnapshotStore: (any CodexAccountUsageSnapshotStoring)? = nil,\n sessionQuotaNotifier: any SessionQuotaNotifying = SessionQuotaNotifier(),\n startupBehavior: StartupBehavior = .automatic,\n environmentBase: [String: String] = ProcessInfo.processInfo.environment)\n {\n self.codexFetcher = fetcher\n self.browserDetection = browserDetection\n self.claudeFetcher = claudeFetcher ?? ClaudeUsageFetcher(browserDetection: browserDetection)\n self.costUsageFetcher = costUsageFetcher\n self.settings = settings\n self.registry = registry\n self.environmentBase = environmentBase\n self.historicalUsageHistoryStore = historicalUsageHistoryStore\n self.planUtilizationHistoryStore = planUtilizationHistoryStore\n self.sessionQuotaNotifier = sessionQuotaNotifier\n self.startupBehavior = startupBehavior.resolved(isRunningTests: Self.isRunningTestsProcess())\n self.codexAccountUsageSnapshotStore = codexAccountUsageSnapshotStore ??\n (self.startupBehavior.automaticallyStartsBackgroundWork ? FileCodexAccountUsageSnapshotStore() : nil)\n self.planUtilizationPersistenceCoordinator = PlanUtilizationHistoryPersistenceCoordinator(\n store: planUtilizationHistoryStore)\n self.providerMetadata = registry.metadata\n self\n .failureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.tokenFailureGates = Dictionary(\n uniqueKeysWithValues: UsageProvider.allCases\n .map { ($0, ConsecutiveFailureGate()) })\n self.providerSpecs = registry.specs(\n settings: settings,\n metadata: self.providerMetadata,\n codexFetcher: fetcher,\n claudeFetcher: self.claudeFetcher,\n browserDetection: browserDetection,\n environmentBase: environmentBase)\n self.providerRuntimes = Dictionary(uniqueKeysWithValues: ProviderCatalog.all.compactMap { implementation in\n implementation.makeRuntime().map { (implementation.id, $0) }\n })\n self.planUtilizationHistory = planUtilizationHistoryStore.load()\n self.weeklyLimitResetDetectorStates = Self.loadWeeklyLimitResetDetectorStates(from: settings.userDefaults)\n if let codexAccountUsageSnapshotStore = self.codexAccountUsageSnapshotStore {\n self.codexAccountSnapshots = codexAccountUsageSnapshotStore.load(\n for: settings.codexVisibleAccountProjection.visibleAccounts)\n }\n self.logStartupState()\n self.bindSettings()\n self.pathDebugInfo = PathDebugSnapshot(\n codexBinary: nil,\n claudeBinary: nil,\n geminiBinary: nil,\n effectivePATH: PathBuilder.effectivePATH(purposes: [.rpc, .tty, .nodeTooling]),\n loginShellPATH: LoginShellPathCache.shared.current?.joined(separator: \":\"))\n guard self.startupBehavior.automaticallyStartsBackgroundWork else { return }\n self.detectVersions()\n self.updateProviderRuntimes()\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n LoginShellPathCache.shared.captureOnce { [weak self] _ in\n Task { @MainActor [weak self] in\n self?.schedulePathDebugInfoRefresh()\n }\n }\n Task { @MainActor [weak self] in\n await self?.refreshHistoricalDatasetIfNeeded()\n }\n Task { await self.refresh() }\n self.startTimer()\n self.startTokenTimer()\n }\n\n private static func isRunningTestsProcess() -> Bool {\n let environment = ProcessInfo.processInfo.environment\n if environment[\"XCTestConfigurationFilePath\"] != nil { return true }\n if environment[\"XCTestSessionIdentifier\"] != nil { return true }\n if environment[\"SWIFT_TESTING_ENABLED\"] != nil { return true }\n return CommandLine.arguments.contains { argument in\n argument.contains(\"xctest\") || argument.contains(\"swift-testing\")\n }\n }\n\n /// Returns the login method (plan type) for the specified provider, if available.\n private func loginMethod(for provider: UsageProvider) -> String? {\n self.snapshots[provider]?.loginMethod(for: provider)\n }\n\n /// Returns true if the Claude account appears to be a subscription (Max, Pro, Ultra, Team).\n /// Returns false for API users or when plan cannot be determined.\n func isClaudeSubscription() -> Bool {\n Self.isSubscriptionPlan(self.loginMethod(for: .claude))\n }\n\n /// Determines if a login method string indicates a Claude subscription plan.\n /// Known subscription indicators: Max, Pro, Ultra, Team (case-insensitive).\n nonisolated static func isSubscriptionPlan(_ loginMethod: String?) -> Bool {\n ClaudePlan.isSubscriptionLoginMethod(loginMethod)\n }\n\n func version(for provider: UsageProvider) -> String? {\n self.versions[provider]\n }\n\n var preferredSnapshot: UsageSnapshot? {\n for provider in self.enabledProviders() {\n if let snap = self.snapshots[provider] { return snap }\n }\n return nil\n }\n\n var iconStyle: IconStyle {\n let enabled = self.enabledProviders()\n if enabled.count > 1 { return .combined }\n if let provider = enabled.first {\n return self.style(for: provider)\n }\n return .codex\n }\n\n var isStale: Bool {\n for provider in self.enabledProviders() where self.errors[provider] != nil {\n return true\n }\n return false\n }\n\n func enabledProviders() -> [UsageProvider] {\n // Use cached enablement to avoid repeated UserDefaults lookups in animation ticks.\n let enabled = self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n let now = Date()\n return enabled.filter { self.isProviderAvailable($0, now: now) }\n }\n\n /// Enabled providers without availability filtering. Used for display (switcher, merge-icons).\n func enabledProvidersForDisplay() -> [UsageProvider] {\n self.settings.enabledProvidersOrdered(metadataByProvider: self.providerMetadata)\n }\n\n /// Providers that should actually participate in background refresh/status/token work.\n func enabledProvidersForBackgroundWork() -> [UsageProvider] {\n self.enabledProviders()\n }\n\n var statusChecksEnabled: Bool {\n self.settings.statusChecksEnabled\n }\n\n func metadata(for provider: UsageProvider) -> ProviderMetadata {\n self.providerMetadata[provider]!\n }\n\n var codexBrowserCookieOrder: BrowserCookieImportOrder {\n self.metadata(for: .codex).browserCookieOrder ?? Browser.defaultImportOrder\n }\n\n func snapshot(for provider: UsageProvider) -> UsageSnapshot? {\n self.snapshots[provider]\n }\n\n func sourceLabel(for provider: UsageProvider) -> String {\n var label = self.lastSourceLabels[provider] ?? \"\"\n if label.isEmpty {\n let descriptor = ProviderDescriptorRegistry.descriptor(for: provider)\n let modes = descriptor.fetchPlan.sourceModes\n if modes.count == 1, let mode = modes.first {\n label = mode.rawValue\n } else {\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: descriptor)\n label = ProviderCatalog.implementation(for: provider)?\n .defaultSourceLabel(context: context)\n ?? \"auto\"\n }\n }\n\n let context = ProviderSourceLabelContext(\n provider: provider,\n settings: self.settings,\n store: self,\n descriptor: ProviderDescriptorRegistry.descriptor(for: provider))\n return ProviderCatalog.implementation(for: provider)?\n .decorateSourceLabel(context: context, baseLabel: label)\n ?? label\n }\n\n func fetchAttempts(for provider: UsageProvider) -> [ProviderFetchAttempt] {\n self.lastFetchAttempts[provider] ?? []\n }\n\n func style(for provider: UsageProvider) -> IconStyle {\n self.providerSpecs[provider]?.style ?? .codex\n }\n\n func isStale(provider: UsageProvider) -> Bool {\n self.errors[provider] != nil\n }\n\n func isEnabled(_ provider: UsageProvider) -> Bool {\n let enabled = self.settings.isProviderEnabledCached(\n provider: provider,\n metadataByProvider: self.providerMetadata)\n guard enabled else { return false }\n return self.isProviderAvailable(provider)\n }\n\n func isProviderAvailable(_ provider: UsageProvider) -> Bool {\n self.isProviderAvailable(provider, now: Date())\n }\n\n private func isProviderAvailable(_ provider: UsageProvider, now: Date) -> Bool {\n guard provider != .codex else { return true }\n\n let configRevision = self.settings.configRevision\n if let cached = self.providerAvailabilityCache[provider],\n cached.isValid(now: now, configRevision: configRevision)\n {\n return cached.available\n }\n\n // Availability should mirror the effective fetch environment, including token-account overrides.\n // Otherwise providers (notably token-account-backed API providers) can fetch successfully but be\n // hidden from the menu because their credentials are not in ProcessInfo's environment.\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n let context = ProviderAvailabilityContext(\n provider: provider,\n settings: self.settings,\n environment: environment)\n let available = ProviderCatalog.implementation(for: provider)?\n .isAvailable(context: context)\n ?? true\n self.providerAvailabilityCache[provider] = ProviderAvailabilityCacheEntry(\n available: available,\n configRevision: configRevision,\n expiresAt: now.addingTimeInterval(self.providerAvailabilityCacheTTL))\n return available\n }\n\n private func invalidateProviderAvailabilityCache() {\n self.providerAvailabilityCache.removeAll(keepingCapacity: true)\n }\n\n func performRuntimeAction(_ action: ProviderRuntimeAction, for provider: UsageProvider) async {\n guard let runtime = self.providerRuntimes[provider] else { return }\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n await runtime.perform(action: action, context: context)\n }\n\n private func updateProviderRuntimes() {\n for (provider, runtime) in self.providerRuntimes {\n let context = ProviderRuntimeContext(provider: provider, settings: self.settings, store: self)\n if self.isEnabled(provider) {\n runtime.start(context: context)\n } else {\n runtime.stop(context: context)\n }\n runtime.settingsDidChange(context: context)\n }\n }\n\n func refresh(forceTokenUsage: Bool = false) async {\n guard !self.isRefreshing else { return }\n self.prepareRefreshState()\n let refreshPhase: ProviderRefreshPhase = self.hasCompletedInitialRefresh ? .regular : .startup\n let displayEnabledProviders = self.enabledProvidersForDisplay()\n let enabledProviderSet = Set(displayEnabledProviders)\n let refreshProviders = self.enabledProvidersForBackgroundWork()\n let availableRefreshProviders = Set(self.enabledProviders())\n let refreshStartedAt = Date()\n\n await ProviderRefreshContext.$current.withValue(refreshPhase) {\n self.isRefreshing = true\n defer {\n self.isRefreshing = false\n self.hasCompletedInitialRefresh = true\n }\n\n self.clearDisabledProviderState(enabledProviders: enabledProviderSet)\n self.clearUnavailableProviderState(\n displayEnabledProviders: enabledProviderSet,\n availableProviders: availableRefreshProviders)\n self.scheduleStorageFootprintRefresh(for: displayEnabledProviders)\n\n await withTaskGroup(of: Void.self) { group in\n for provider in refreshProviders {\n group.addTask { await self.refreshProvider(provider) }\n if availableRefreshProviders.contains(provider) {\n group.addTask { await self.refreshStatus(provider) }\n }\n }\n group.addTask { await self.refreshCreditsIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt) }\n }\n\n // Token-cost usage can be slow; run it outside the refresh group so we don't block menu updates.\n self.scheduleTokenRefresh(force: forceTokenUsage)\n\n // OpenAI web scrape depends on the current Codex account email (which can change after login/account\n // switch). Run this after Codex usage refresh so we don't accidentally scrape with stale credentials.\n self.syncOpenAIWebState()\n let refreshPolicy = OpenAIWebRefreshPolicyContext(\n accessEnabled: self.isEnabled(.codex) &&\n self.settings.openAIWebAccessEnabled &&\n self.settings.codexCookieSource.isEnabled,\n batterySaverEnabled: self.settings.openAIWebBatterySaverEnabled,\n force: forceTokenUsage)\n let shouldRefreshOpenAIWeb = Self.shouldRunOpenAIWebRefresh(refreshPolicy)\n self.openAIWebLogger.debug(\n \"OpenAI web refresh gate\",\n metadata: [\n \"allowed\": shouldRefreshOpenAIWeb ? \"1\" : \"0\",\n \"accessEnabled\": refreshPolicy.accessEnabled ? \"1\" : \"0\",\n \"batterySaverEnabled\": refreshPolicy.batterySaverEnabled ? \"1\" : \"0\",\n \"force\": refreshPolicy.force ? \"1\" : \"0\",\n \"interaction\": ProviderInteractionContext.current == .userInitiated ? \"user\" : \"background\",\n \"phase\": refreshPhase == .startup ? \"startup\" : \"regular\",\n ])\n if shouldRefreshOpenAIWeb {\n let codexDashboardGuard = self.currentCodexOpenAIWebRefreshGuard()\n await self.refreshOpenAIDashboardIfNeeded(\n force: forceTokenUsage,\n expectedGuard: codexDashboardGuard)\n }\n\n if forceTokenUsage, self.openAIDashboardRequiresLogin {\n await self.refreshProvider(.codex)\n await self.refreshCreditsIfNeeded(minimumSnapshotUpdatedAt: refreshStartedAt)\n }\n\n self.persistWidgetSnapshot(reason: \"refresh\")\n }\n }\n\n /// For demo/testing: drop the snapshot so the loading animation plays, then restore the last snapshot.\n func replayLoadingAnimation(duration: TimeInterval = 3) {\n let current = self.preferredSnapshot\n self.snapshots.removeAll()\n self.debugForceAnimation = true\n Task { @MainActor in\n try? await Task.sleep(for: .seconds(duration))\n if let current, let provider = self.enabledProviders().first {\n self.snapshots[provider] = current\n }\n self.debugForceAnimation = false\n }\n }\n\n // MARK: - Private\n\n private func bindSettings() {\n self.observeSettingsChanges()\n }\n\n private func startTimer() {\n self.timerTask?.cancel()\n guard let wait = self.settings.refreshFrequency.seconds else { return }\n\n // Background poller so the menu stays responsive; canceled when settings change or store deallocates.\n self.timerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.refresh()\n }\n }\n }\n\n private func startTokenTimer() {\n self.tokenTimerTask?.cancel()\n let wait = self.tokenFetchTTL\n self.tokenTimerTask = Task.detached(priority: .utility) { [weak self] in\n while !Task.isCancelled {\n try? await Task.sleep(for: .seconds(wait))\n await self?.scheduleTokenRefresh(force: false)\n }\n }\n }\n\n private func scheduleTokenRefresh(force: Bool) {\n if force {\n self.tokenRefreshSequenceTask?.cancel()\n self.tokenRefreshSequenceTask = nil\n } else if self.tokenRefreshSequenceTask != nil {\n return\n }\n\n let providers = self.enabledProvidersForBackgroundWork()\n self.tokenRefreshSequenceTask = Task(priority: .utility) { [weak self] in\n guard let self else { return }\n defer {\n Task { @MainActor [weak self] in\n self?.tokenRefreshSequenceTask = nil\n }\n }\n for provider in providers {\n if Task.isCancelled { break }\n await self.refreshTokenUsage(provider, force: force)\n }\n }\n }\n\n deinit {\n self.timerTask?.cancel()\n self.tokenTimerTask?.cancel()\n self.tokenRefreshSequenceTask?.cancel()\n self.storageRefreshTask?.cancel()\n self.codexPlanHistoryBackfillTask?.cancel()\n }\n\n enum SessionQuotaWindowSource: String {\n case primary\n case copilotSecondaryFallback\n }\n\n struct QuotaWarningStateKey: Hashable {\n let provider: UsageProvider\n let window: QuotaWarningWindow\n }\n\n struct QuotaWarningState {\n var lastRemaining: Double?\n var firedThresholds: Set<Int> = []\n }\n\n private func sessionQuotaWindow(\n provider: UsageProvider,\n snapshot: UsageSnapshot) -> (window: RateWindow, source: SessionQuotaWindowSource)?\n {\n if let primary = snapshot.primary, Self.isSessionWindow(primary) {\n return (primary, .primary)\n }\n if provider == .copilot, let secondary = snapshot.secondary {\n return (secondary, .copilotSecondaryFallback)\n }\n return nil\n }\n\n private static func isSessionWindow(_ window: RateWindow) -> Bool {\n guard let minutes = window.windowMinutes else { return true }\n return minutes <= 6 * 60\n }\n\n func handleSessionQuotaTransition(provider: UsageProvider, snapshot: UsageSnapshot) {\n // Session quota notifications are tied to the primary session window. Copilot free plans can\n // expose only chat quota, so allow Copilot to fall back to secondary for transition tracking.\n guard let sessionWindow = self.sessionQuotaWindow(provider: provider, snapshot: snapshot) else {\n self.lastKnownSessionRemaining.removeValue(forKey: provider)\n self.lastKnownSessionWindowSource.removeValue(forKey: provider)\n return\n }\n let currentRemaining = sessionWindow.window.remainingPercent\n let currentSource = sessionWindow.source\n let previousRemaining = self.lastKnownSessionRemaining[provider]\n let previousSource = self.lastKnownSessionWindowSource[provider]\n\n if let previousSource, previousSource != currentSource {\n let providerText = provider.rawValue\n self.sessionQuotaLogger.debug(\n \"session window source changed: provider=\\(providerText) prevSource=\\(previousSource.rawValue) \" +\n \"currSource=\\(currentSource.rawValue) curr=\\(currentRemaining)\")\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n return\n }\n\n defer {\n self.lastKnownSessionRemaining[provider] = currentRemaining\n self.lastKnownSessionWindowSource[provider] = currentSource\n }\n\n guard self.settings.sessionQuotaNotificationsEnabled else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"notifications disabled: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n guard previousRemaining != nil else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) {\n let providerText = provider.rawValue\n let message = \"startup depleted: provider=\\(providerText) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n self.sessionQuotaNotifier.post(transition: .depleted, provider: provider, badge: nil)\n }\n return\n }\n\n let transition = SessionQuotaNotificationLogic.transition(\n previousRemaining: previousRemaining,\n currentRemaining: currentRemaining)\n guard transition != .none else {\n if SessionQuotaNotificationLogic.isDepleted(currentRemaining) ||\n SessionQuotaNotificationLogic.isDepleted(previousRemaining)\n {\n let providerText = provider.rawValue\n let message =\n \"no transition: provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.debug(message)\n }\n return\n }\n\n let providerText = provider.rawValue\n let transitionText = String(describing: transition)\n let message =\n \"transition \\(transitionText): provider=\\(providerText) \" +\n \"prev=\\(previousRemaining ?? -1) curr=\\(currentRemaining)\"\n self.sessionQuotaLogger.info(message)\n\n self.sessionQuotaNotifier.post(transition: transition, provider: provider, badge: nil)\n }\n\n func handleQuotaWarningTransitions(provider: UsageProvider, snapshot: UsageSnapshot) {\n guard self.settings.quotaWarningNotificationsEnabled else { return }\n\n let accountDisplayName = self.quotaWarningAccountDisplayName(provider: provider, snapshot: snapshot)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .session,\n rateWindow: snapshot.primary,\n accountDisplayName: accountDisplayName)\n self.handleQuotaWarningTransition(\n provider: provider,\n window: .weekly,\n rateWindow: snapshot.secondary,\n accountDisplayName: accountDisplayName)\n }\n\n private func handleQuotaWarningTransition(\n provider: UsageProvider,\n window: QuotaWarningWindow,\n rateWindow: RateWindow?,\n accountDisplayName: String?)\n {\n let key = QuotaWarningStateKey(provider: provider, window: window)\n guard self.settings.quotaWarningEnabled(provider: provider, window: window) else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n guard let rateWindow else {\n self.quotaWarningState.removeValue(forKey: key)\n return\n }\n\n let thresholds = self.settings.resolvedQuotaWarningThresholds(provider: provider, window: window)\n let currentRemaining = rateWindow.remainingPercent\n var state = self.quotaWarningState[key] ?? QuotaWarningState()\n let cleared = QuotaWarningNotificationLogic.thresholdsToClear(\n currentRemaining: currentRemaining,\n alreadyFired: state.firedThresholds)\n state.firedThresholds.subtract(cleared)\n\n if let threshold = QuotaWarningNotificationLogic.crossedThreshold(\n previousRemaining: state.lastRemaining,\n currentRemaining: currentRemaining,\n thresholds: thresholds,\n alreadyFired: state.firedThresholds)\n {\n state.firedThresholds.formUnion(QuotaWarningNotificationLogic.firedThresholdsAfterWarning(\n threshold: threshold,\n thresholds: thresholds))\n self.sessionQuotaNotifier.postQuotaWarning(\n event: QuotaWarningEvent(\n window: window,\n threshold: threshold,\n currentRemaining: currentRemaining,\n accountDisplayName: accountDisplayName),\n provider: provider,\n soundEnabled: self.settings.quotaWarningSoundEnabled)\n }\n\n state.lastRemaining = currentRemaining\n self.quotaWarningState[key] = state\n }\n\n private func quotaWarningAccountDisplayName(provider: UsageProvider, snapshot: UsageSnapshot) -> String? {\n guard !self.settings.hidePersonalInfo else { return nil }\n let account = snapshot.accountEmail(for: provider)?\n .trimmingCharacters(in: .whitespacesAndNewlines)\n guard let account, !account.isEmpty else { return nil }\n return account\n }\n\n private func refreshStatus(_ provider: UsageProvider) async {\n guard self.settings.statusChecksEnabled else { return }\n guard let meta = self.providerMetadata[provider] else { return }\n\n do {\n let status: ProviderStatus\n if let urlString = meta.statusPageURL, let baseURL = URL(string: urlString) {\n status = try await Self.fetchStatus(from: baseURL)\n } else if let productID = meta.statusWorkspaceProductID {\n status = try await Self.fetchWorkspaceStatus(productID: productID)\n } else {\n return\n }\n await MainActor.run { self.statuses[provider] = status }\n } catch {\n // Keep the previous status to avoid flapping when the API hiccups.\n await MainActor.run {\n if self.statuses[provider] == nil {\n self.statuses[provider] = ProviderStatus(\n indicator: .unknown,\n description: error.localizedDescription,\n updatedAt: nil)\n }\n }\n }\n }\n}\n\nextension UsageStore {\n func debugDumpClaude() async {\n let fetcher = ClaudeUsageFetcher(\n browserDetection: self.browserDetection,\n keepCLISessionsAlive: self.settings.debugKeepCLISessionsAlive)\n let output = await fetcher.debugRawProbe(model: \"sonnet\")\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(\"codexbar-claude-probe.txt\")\n try? output.write(to: url, atomically: true, encoding: .utf8)\n await MainActor.run {\n let snippet = String(output.prefix(180)).replacingOccurrences(of: \"\\n\", with: \" \")\n self.errors[.claude] = \"[Claude] \\(snippet) (saved: \\(url.path))\"\n NSWorkspace.shared.open(url)\n }\n }\n\n func dumpLog(toFileFor provider: UsageProvider) async -> URL? {\n let text = await self.debugLog(for: provider)\n let filename = \"codexbar-\\(provider.rawValue)-probe.txt\"\n let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(filename)\n do {\n try text.write(to: url, atomically: true, encoding: .utf8)\n _ = await MainActor.run { NSWorkspace.shared.open(url) }\n return url\n } catch {\n await MainActor.run {\n self.errors[provider] = \"Failed to save log: \\(error.localizedDescription)\"\n }\n return nil\n }\n }\n\n func debugAugmentDump() async -> String {\n await AugmentStatusProbe.latestDumps()\n }\n\n func debugLog(for provider: UsageProvider) async -> String {\n if let cached = self.probeLogs[provider], !cached.isEmpty {\n return cached\n }\n\n let claudeWebExtrasEnabled = self.settings.claudeWebExtrasEnabled\n let claudeUsageDataSource = self.settings.claudeUsageDataSource\n let claudeCookieSource = self.settings.claudeCookieSource\n let claudeCookieHeader = self.settings.claudeCookieHeader\n let claudeDebugConfiguration: ClaudeDebugLogConfiguration? = if provider == .claude {\n await self.makeClaudeDebugConfiguration(\n fallbackUsageDataSource: claudeUsageDataSource,\n fallbackWebExtrasEnabled: claudeWebExtrasEnabled,\n fallbackCookieSource: claudeCookieSource,\n fallbackCookieHeader: claudeCookieHeader)\n } else {\n nil\n }\n let cursorCookieSource = self.settings.cursorCookieSource\n let cursorCookieHeader = self.settings.cursorCookieHeader\n let ampCookieSource = self.settings.ampCookieSource\n let ampCookieHeader = self.settings.ampCookieHeader\n let ollamaCookieSource = self.settings.ollamaCookieSource\n let ollamaCookieHeader = self.settings.ollamaCookieHeader\n let processEnvironment = self.environmentBase\n let openAIDebugContext = self.openAIAPIKeyDebugContext(processEnvironment: processEnvironment)\n let openRouterDebugContext = self.openRouterAPIKeyDebugContext(processEnvironment: processEnvironment)\n let elevenLabsDebugContext = self.elevenLabsAPIKeyDebugContext(processEnvironment: processEnvironment)\n let deepSeekHasEnvToken = DeepSeekSettingsReader.apiKey(environment: processEnvironment) != nil\n let deepSeekHasTokenAccount = self.settings.selectedTokenAccount(for: .deepseek) != nil\n let deepSeekEnvironment = ProviderRegistry.makeEnvironment(\n base: processEnvironment,\n provider: .deepseek,\n settings: self.settings,\n tokenOverride: nil)\n let codexFetcher = self.codexFetcher\n let browserDetection = self.browserDetection\n let claudeDebugExecutionContext = self.currentClaudeDebugExecutionContext()\n let text = await Task.detached(priority: .utility) { () -> String in\n let unimplementedDebugLogMessages: [UsageProvider: String] = [\n .gemini: \"Gemini debug log not yet implemented\",\n .antigravity: \"Antigravity debug log not yet implemented\",\n .opencode: \"OpenCode debug log not yet implemented\",\n .alibaba: \"Alibaba Coding Plan debug log not yet implemented\",\n .factory: \"Droid debug log not yet implemented\",\n .copilot: \"Copilot debug log not yet implemented\",\n .manus: \"Manus debug log not yet implemented\",\n .vertexai: \"Vertex AI debug log not yet implemented\",\n .kilo: \"Kilo debug log not yet implemented\",\n .kiro: \"Kiro debug log not yet implemented\",\n .kimi: \"Kimi debug log not yet implemented\",\n .kimik2: \"Kimi K2 debug log not yet implemented\",\n .jetbrains: \"JetBrains AI debug log not yet implemented\",\n .mimo: \"Xiaomi MiMo debug log not yet implemented\",\n .doubao: \"Doubao debug log not yet implemented\",\n .venice: \"Venice debug log not yet implemented\",\n .commandcode: \"Command Code debug log not yet implemented\",\n .stepfun: \"StepFun debug log not yet implemented\",\n .bedrock: \"Bedrock debug log not yet implemented\",\n .grok: \"Grok debug log not yet implemented\",\n .deepgram: \"Deepgram debug log not yet implemented\",\n ]\n let buildText = {\n switch provider {\n case .codex:\n return await codexFetcher.debugRawRateLimits()\n case .openai:\n return Self.apiKeyDebugLine(openAIDebugContext)\n case .claude:\n guard let claudeDebugConfiguration else {\n return \"Claude debug log configuration unavailable\"\n }\n return await claudeDebugExecutionContext.apply {\n await Self.debugClaudeLog(\n browserDetection: browserDetection,\n configuration: claudeDebugConfiguration)\n }\n case .zai:\n let resolution = ProviderTokenResolver.zaiResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"Z_AI_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .synthetic:\n let resolution = ProviderTokenResolver.syntheticResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"SYNTHETIC_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .cursor:\n return await Self.debugCursorLog(\n browserDetection: browserDetection,\n cursorCookieSource: cursorCookieSource,\n cursorCookieHeader: cursorCookieHeader)\n case .minimax:\n let tokenResolution = ProviderTokenResolver.minimaxTokenResolution()\n let cookieResolution = ProviderTokenResolver.minimaxCookieResolution()\n let tokenSource = tokenResolution?.source.rawValue ?? \"none\"\n let cookieSource = cookieResolution?.source.rawValue ?? \"none\"\n return \"MINIMAX_API_KEY=\\(tokenResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(tokenSource) MINIMAX_COOKIE=\\(cookieResolution == nil ? \"missing\" : \"present\") \" +\n \"source=\\(cookieSource)\"\n case .alibaba:\n let resolution = ProviderTokenResolver.alibabaTokenResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"ALIBABA_CODING_PLAN_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .augment:\n return await Self.debugAugmentLog()\n case .amp:\n return await Self.debugAmpLog(\n browserDetection: browserDetection,\n ampCookieSource: ampCookieSource,\n ampCookieHeader: ampCookieHeader)\n case .ollama:\n return await Self.debugOllamaLog(\n browserDetection: browserDetection,\n ollamaCookieSource: ollamaCookieSource,\n ollamaCookieHeader: ollamaCookieHeader)\n case .openrouter:\n return Self.apiKeyDebugLine(openRouterDebugContext)\n case .elevenlabs:\n return Self.apiKeyDebugLine(elevenLabsDebugContext)\n case .warp:\n let resolution = ProviderTokenResolver.warpResolution()\n let hasAny = resolution != nil\n let source = resolution?.source.rawValue ?? \"none\"\n return \"WARP_API_KEY=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n case .deepseek:\n return Self.apiKeyDebugLine(\n label: \"DEEPSEEK_API_KEY\",\n resolution: ProviderTokenResolver.deepseekResolution(environment: deepSeekEnvironment),\n configToken: nil,\n hasEnvToken: deepSeekHasEnvToken,\n hasTokenAccount: deepSeekHasTokenAccount)\n case .gemini, .antigravity, .opencode, .opencodego, .factory, .copilot, .vertexai, .kilo, .kiro, .kimi,\n .kimik2, .moonshot, .jetbrains, .perplexity, .mimo, .doubao, .abacus, .mistral, .codebuff, .crof,\n .windsurf, .venice, .manus, .commandcode, .stepfun, .bedrock, .grok, .deepgram:\n return unimplementedDebugLogMessages[provider] ?? \"Debug log not yet implemented\"\n }\n }\n return await claudeDebugExecutionContext.apply {\n await buildText()\n }\n }.value\n self.probeLogs[provider] = text\n return text\n }\n\n private func makeClaudeDebugConfiguration(\n fallbackUsageDataSource: ClaudeUsageDataSource,\n fallbackWebExtrasEnabled: Bool,\n fallbackCookieSource: ProviderCookieSource,\n fallbackCookieHeader: String) async -> ClaudeDebugLogConfiguration\n {\n await MainActor.run {\n let sourceMode = self.sourceMode(for: .claude)\n let snapshot = ProviderRegistry.makeSettingsSnapshot(settings: self.settings, tokenOverride: nil)\n let environment = ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: .claude,\n settings: self.settings,\n tokenOverride: nil)\n let claudeSettings = snapshot.claude ?? ProviderSettingsSnapshot.ClaudeProviderSettings(\n usageDataSource: fallbackUsageDataSource,\n webExtrasEnabled: fallbackWebExtrasEnabled,\n cookieSource: fallbackCookieSource,\n manualCookieHeader: fallbackCookieHeader)\n return ClaudeDebugLogConfiguration(\n runtime: CodexBarCore.ProviderRuntime.app,\n sourceMode: sourceMode,\n environment: environment,\n webExtrasEnabled: claudeSettings.webExtrasEnabled,\n usageDataSource: claudeSettings.usageDataSource,\n cookieSource: claudeSettings.cookieSource,\n cookieHeader: claudeSettings.manualCookieHeader ?? \"\",\n keepCLISessionsAlive: snapshot.debugKeepCLISessionsAlive)\n }\n }\n\n private struct ClaudeDebugExecutionContext {\n let interaction: ProviderInteraction\n let refreshPhase: ProviderRefreshPhase\n #if DEBUG\n let keychainServiceOverride: String?\n let credentialsURLOverride: URL?\n let testingOverrides: ClaudeOAuthCredentialsStore.TestingOverridesSnapshot\n let keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.DeniedUntilStore?\n let keychainPromptModeOverride: ClaudeOAuthKeychainPromptMode?\n let keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategy?\n let cliPathOverride: String?\n let statusFetchOverride: ClaudeStatusProbe.FetchOverride?\n #endif\n\n func apply<T>(_ operation: () async -> T) async -> T {\n await ProviderInteractionContext.$current.withValue(self.interaction) {\n await ProviderRefreshContext.$current.withValue(self.refreshPhase) {\n #if DEBUG\n return await KeychainCacheStore.withServiceOverrideForTesting(self.keychainServiceOverride) {\n await ClaudeOAuthCredentialsStore\n .withCredentialsURLOverrideForTesting(self.credentialsURLOverride) {\n await ClaudeOAuthCredentialsStore\n .withTestingOverridesSnapshotForTask(self.testingOverrides) {\n await ClaudeOAuthKeychainAccessGate\n .withDeniedUntilStoreOverrideForTesting(self\n .keychainDeniedUntilStoreOverride)\n {\n await ClaudeOAuthKeychainPromptPreference\n .withTaskOverrideForTesting(self.keychainPromptModeOverride) {\n await ClaudeOAuthKeychainReadStrategyPreference\n .withTaskOverrideForTesting(self\n .keychainReadStrategyOverride)\n {\n await ClaudeCLIResolver\n .withResolvedBinaryPathOverrideForTesting(self\n .cliPathOverride)\n {\n await ClaudeStatusProbe\n .withFetchOverrideForTesting(self\n .statusFetchOverride)\n {\n await operation()\n }\n }\n }\n }\n }\n }\n }\n }\n #else\n return await operation()\n #endif\n }\n }\n }\n }\n\n private func currentClaudeDebugExecutionContext() -> ClaudeDebugExecutionContext {\n #if DEBUG\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current,\n keychainServiceOverride: KeychainCacheStore.currentServiceOverrideForTesting,\n credentialsURLOverride: ClaudeOAuthCredentialsStore.currentCredentialsURLOverrideForTesting,\n testingOverrides: ClaudeOAuthCredentialsStore.currentTestingOverridesSnapshotForTask,\n keychainDeniedUntilStoreOverride: ClaudeOAuthKeychainAccessGate.currentDeniedUntilStoreOverrideForTesting,\n keychainPromptModeOverride: ClaudeOAuthKeychainPromptPreference.currentTaskOverrideForTesting,\n keychainReadStrategyOverride: ClaudeOAuthKeychainReadStrategyPreference.currentTaskOverrideForTesting,\n cliPathOverride: ClaudeCLIResolver.currentResolvedBinaryPathOverrideForTesting,\n statusFetchOverride: ClaudeStatusProbe.currentFetchOverrideForTesting)\n #else\n ClaudeDebugExecutionContext(\n interaction: ProviderInteractionContext.current,\n refreshPhase: ProviderRefreshContext.current)\n #endif\n }\n\n private struct APIKeyDebugContext {\n let label: String\n let resolution: ProviderTokenResolution?\n let configToken: String?\n let hasEnvToken: Bool\n let hasTokenAccount: Bool\n }\n\n private func openAIAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openai)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openai,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENAI_API_KEY\",\n resolution: ProviderTokenResolver.openAIAPIResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenAIAPISettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func openRouterAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .openrouter)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .openrouter,\n config: config)\n return APIKeyDebugContext(\n label: \"OPENROUTER_API_KEY\",\n resolution: ProviderTokenResolver.openRouterResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: OpenRouterSettingsReader.apiToken(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private func elevenLabsAPIKeyDebugContext(processEnvironment: [String: String]) -> APIKeyDebugContext {\n let config = self.settings.providerConfig(for: .elevenlabs)\n let environment = ProviderConfigEnvironment.applyAPIKeyOverride(\n base: processEnvironment,\n provider: .elevenlabs,\n config: config)\n return APIKeyDebugContext(\n label: \"ELEVENLABS_API_KEY\",\n resolution: ProviderTokenResolver.elevenLabsResolution(environment: environment),\n configToken: config?.sanitizedAPIKey,\n hasEnvToken: ElevenLabsSettingsReader.apiKey(environment: processEnvironment) != nil,\n hasTokenAccount: false)\n }\n\n private nonisolated static func apiKeyDebugLine(_ context: APIKeyDebugContext) -> String {\n self.apiKeyDebugLine(\n label: context.label,\n resolution: context.resolution,\n configToken: context.configToken,\n hasEnvToken: context.hasEnvToken,\n hasTokenAccount: context.hasTokenAccount)\n }\n\n private nonisolated static func apiKeyDebugLine(\n label: String,\n resolution: ProviderTokenResolution?,\n configToken: String?,\n hasEnvToken: Bool,\n hasTokenAccount: Bool = false) -> String\n {\n let hasAny = resolution != nil\n let hasConfigToken = !(configToken?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true)\n let source: String = if resolution == nil {\n \"none\"\n } else if hasTokenAccount, hasEnvToken {\n \"settings-token-account (overrides env)\"\n } else if hasTokenAccount {\n \"settings-token-account\"\n } else if hasConfigToken, hasEnvToken {\n \"settings-config (overrides env)\"\n } else if hasConfigToken {\n \"settings-config\"\n } else {\n resolution?.source.rawValue ?? \"environment\"\n }\n return \"\\(label)=\\(hasAny ? \"present\" : \"missing\") source=\\(source)\"\n }\n\n private static func debugCursorLog(\n browserDetection: BrowserDetection,\n cursorCookieSource: ProviderCookieSource,\n cursorCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n var lines: [String] = []\n\n do {\n let probe = CursorStatusProbe(browserDetection: browserDetection)\n let snapshot: CursorStatusSnapshot = if cursorCookieSource == .manual,\n let normalizedHeader = CookieHeaderNormalizer\n .normalize(cursorCookieHeader)\n {\n try await probe.fetchWithManualCookies(normalizedHeader)\n } else {\n try await probe.fetch { msg in lines.append(\"[cursor-cookie] \\(msg)\") }\n }\n\n lines.append(\"\")\n lines.append(\"Cursor Status Summary:\")\n lines.append(\"membershipType=\\(snapshot.membershipType ?? \"nil\")\")\n lines.append(\"accountEmail=\\(snapshot.accountEmail ?? \"nil\")\")\n lines.append(\"planPercentUsed=\\(snapshot.planPercentUsed)%\")\n lines.append(\"planUsedUSD=$\\(snapshot.planUsedUSD)\")\n lines.append(\"planLimitUSD=$\\(snapshot.planLimitUSD)\")\n lines.append(\"onDemandUsedUSD=$\\(snapshot.onDemandUsedUSD)\")\n lines.append(\"onDemandLimitUSD=\\(snapshot.onDemandLimitUSD.map { \"$\\($0)\" } ?? \"nil\")\")\n if let teamUsed = snapshot.teamOnDemandUsedUSD {\n lines.append(\"teamOnDemandUsedUSD=$\\(teamUsed)\")\n }\n if let teamLimit = snapshot.teamOnDemandLimitUSD {\n lines.append(\"teamOnDemandLimitUSD=$\\(teamLimit)\")\n }\n lines.append(\"billingCycleEnd=\\(snapshot.billingCycleEnd?.description ?? \"nil\")\")\n\n if let rawJSON = snapshot.rawJSON {\n lines.append(\"\")\n lines.append(\"Raw API Response:\")\n lines.append(rawJSON)\n }\n\n return lines.joined(separator: \"\\n\")\n } catch {\n lines.append(\"\")\n lines.append(\"Cursor probe failed: \\(error.localizedDescription)\")\n return lines.joined(separator: \"\\n\")\n }\n }\n }\n\n private static func debugAugmentLog() async -> String {\n await runWithTimeout(seconds: 15) {\n let probe = AugmentStatusProbe()\n return await probe.debugRawProbe()\n }\n }\n\n private static func debugAmpLog(\n browserDetection: BrowserDetection,\n ampCookieSource: ProviderCookieSource,\n ampCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = AmpUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ampCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ampCookieHeader)\n : nil\n return await fetcher.debugRawProbe(cookieHeaderOverride: manualHeader)\n }\n }\n\n private static func debugOllamaLog(\n browserDetection: BrowserDetection,\n ollamaCookieSource: ProviderCookieSource,\n ollamaCookieHeader: String) async -> String\n {\n await runWithTimeout(seconds: 15) {\n let fetcher = OllamaUsageFetcher(browserDetection: browserDetection)\n let manualHeader = ollamaCookieSource == .manual\n ? CookieHeaderNormalizer.normalize(ollamaCookieHeader)\n : nil\n return await fetcher.debugRawProbe(\n cookieHeaderOverride: manualHeader,\n manualCookieMode: ollamaCookieSource == .manual)\n }\n }\n\n private func detectVersions() {\n let implementations = ProviderCatalog.all\n let browserDetection = self.browserDetection\n Task { @MainActor [weak self] in\n let resolved = await Task.detached { () -> [UsageProvider: String] in\n var resolved: [UsageProvider: String] = [:]\n await withTaskGroup(of: (UsageProvider, String?).self) { group in\n for implementation in implementations {\n let context = ProviderVersionContext(\n provider: implementation.id,\n browserDetection: browserDetection)\n group.addTask {\n await (implementation.id, implementation.detectVersion(context: context))\n }\n }\n for await (provider, version) in group {\n guard let version, !version.isEmpty else { continue }\n resolved[provider] = version\n }\n }\n return resolved\n }.value\n self?.versions = resolved\n }\n }\n\n @MainActor\n private func schedulePathDebugInfoRefresh() {\n self.pathDebugRefreshTask?.cancel()\n self.pathDebugRefreshTask = Task { [weak self] in\n do {\n try await Task.sleep(nanoseconds: 150_000_000)\n } catch {\n return\n }\n await self?.refreshPathDebugInfo()\n }\n }\n\n private func runBackgroundSnapshot(\n _ snapshot: @escaping @Sendable () async -> PathDebugSnapshot) async\n {\n let result = await snapshot()\n await MainActor.run {\n self.pathDebugInfo = result\n }\n }\n\n private func refreshPathDebugInfo() async {\n await self.runBackgroundSnapshot {\n await PathBuilder.debugSnapshotAsync(purposes: [.rpc, .tty, .nodeTooling])\n }\n }\n\n func clearCostUsageCache() async -> String? {\n let errorMessage: String? = await Task.detached(priority: .utility) {\n let fm = FileManager.default\n let cacheDirs = [\n Self.costUsageCacheDirectory(fileManager: fm),\n ]\n\n for cacheDir in cacheDirs {\n do {\n try fm.removeItem(at: cacheDir)\n } catch let error as NSError {\n if error.domain == NSCocoaErrorDomain, error.code == NSFileNoSuchFileError { continue }\n return error.localizedDescription\n }\n }\n return nil\n }.value\n\n guard errorMessage == nil else { return errorMessage }\n\n self.tokenSnapshots.removeAll()\n self.tokenErrors.removeAll()\n self.lastTokenFetchAt.removeAll()\n self.lastTokenFetchScope.removeAll()\n self.tokenFailureGates[.codex]?.reset()\n self.tokenFailureGates[.claude]?.reset()\n return nil\n }\n\n private func refreshTokenUsage(_ provider: UsageProvider, force: Bool) async {\n guard provider == .codex || provider == .claude || provider == .vertexai || provider == .bedrock else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.settings.costUsageEnabled else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard self.isEnabled(provider) else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.reset()\n self.lastTokenFetchAt.removeValue(forKey: provider)\n self.lastTokenFetchScope.removeValue(forKey: provider)\n return\n }\n\n guard !self.tokenRefreshInFlight.contains(provider) else { return }\n\n let now = Date()\n let costScope = self.tokenCostScope(for: provider)\n if !force,\n let last = self.lastTokenFetchAt[provider],\n self.lastTokenFetchScope[provider] == costScope.signature,\n now.timeIntervalSince(last) < self.tokenFetchTTL\n {\n return\n }\n self.lastTokenFetchAt[provider] = now\n self.lastTokenFetchScope[provider] = costScope.signature\n self.tokenRefreshInFlight.insert(provider)\n defer { self.tokenRefreshInFlight.remove(provider) }\n\n let startedAt = Date()\n let providerText = provider.rawValue\n self.tokenCostLogger\n .debug(\"cost usage start provider=\\(providerText) force=\\(force)\")\n\n do {\n let fetcher = self.costUsageFetcher\n let timeoutSeconds = self.tokenFetchTimeout\n let environment = provider == .bedrock\n ? ProviderRegistry.makeEnvironment(\n base: self.environmentBase,\n provider: provider,\n settings: self.settings,\n tokenOverride: nil)\n : self.environmentBase\n // CostUsageFetcher scans local Codex session logs from this machine. That data is\n // intentionally presented as provider-level local telemetry rather than managed-account\n // remote state, so managed Codex account selection does not retarget this fetch.\n // If the UI later needs account-scoped token history, it should label and source that\n // separately instead of silently changing the meaning of this section.\n let snapshot = try await withThrowingTaskGroup(of: CostUsageTokenSnapshot.self) { group in\n group.addTask(priority: .utility) {\n try await fetcher.loadTokenSnapshot(\n provider: provider,\n environment: environment,\n now: now,\n forceRefresh: force,\n allowVertexClaudeFallback: !self.isEnabled(.claude),\n codexHomePath: costScope.codexHomePath)\n }\n group.addTask {\n try await Task.sleep(nanoseconds: UInt64(timeoutSeconds * 1_000_000_000))\n throw CostUsageError.timedOut(seconds: Int(timeoutSeconds))\n }\n defer { group.cancelAll() }\n guard let snapshot = try await group.next() else { throw CancellationError() }\n return snapshot\n }\n\n guard !snapshot.daily.isEmpty else {\n self.tokenSnapshots.removeValue(forKey: provider)\n self.tokenErrors[provider] = Self.tokenCostNoDataMessage(for: provider)\n self.tokenFailureGates[provider]?.recordSuccess()\n return\n }\n let duration = Date().timeIntervalSince(startedAt)\n let sessionCost = snapshot.sessionCostUSD.map(UsageFormatter.usdString) ?? \"—\"\n let monthCost = snapshot.last30DaysCostUSD.map(UsageFormatter.usdString) ?? \"—\"\n let durationText = String(format: \"%.2f\", duration)\n let message =\n \"cost usage success provider=\\(providerText) \" +\n \"duration=\\(durationText)s \" +\n \"today=\\(sessionCost) \" +\n \"30d=\\(monthCost)\"\n self.tokenCostLogger.info(message)\n self.tokenSnapshots[provider] = snapshot\n self.tokenErrors[provider] = nil\n self.tokenFailureGates[provider]?.recordSuccess()\n self.persistWidgetSnapshot(reason: \"token-usage\")\n } catch {\n if error is CancellationError { return }\n let duration = Date().timeIntervalSince(startedAt)\n let msg = error.localizedDescription\n let durationText = String(format: \"%.2f\", duration)\n let message = \"cost usage failed provider=\\(providerText) duration=\\(durationText)s error=\\(msg)\"\n self.tokenCostLogger.error(message)\n let hadPriorData = self.tokenSnapshots[provider] != nil\n let shouldSurface = self.tokenFailureGates[provider]?\n .shouldSurfaceError(onFailureWithPriorData: hadPriorData) ?? true\n if shouldSurface {\n self.tokenErrors[provider] = error.localizedDescription\n self.tokenSnapshots.removeValue(forKey: provider)\n } else {\n self.tokenErrors[provider] = nil\n }\n }\n }\n}\n"}}, "Sources/CodexBarCore/Providers/DeepSeek/DeepSeekSettingsReader.swift": {"e531e1c8a1aac332f8cc40b6614afc42cfd08663": {"t": 1785745900.4809499, "n": 1098, "h": "d8c80dd222ab4880", "c": "import Foundation\n\npublic struct DeepSeekSettingsReader: Sendable {\n public static let apiKeyEnvironmentKey = \"DEEPSEEK_API_KEY\"\n public static let apiKeyEnvironmentKeys = [Self.apiKeyEnvironmentKey, \"DEEPSEEK_KEY\"]\n\n public static func apiKey(\n environment: [String: String] = ProcessInfo.processInfo.environment) -> String?\n {\n for key in self.apiKeyEnvironmentKeys {\n guard let raw = environment[key]?.trimmingCharacters(in: .whitespacesAndNewlines),\n !raw.isEmpty\n else {\n continue\n }\n let cleaned = Self.cleaned(raw)\n if !cleaned.isEmpty {\n return cleaned\n }\n }\n return nil\n }\n\n private static func cleaned(_ raw: String) -> String {\n var value = raw\n if (value.hasPrefix(\"\\\"\") && value.hasSuffix(\"\\\"\")) ||\n (value.hasPrefix(\"'\") && value.hasSuffix(\"'\"))\n {\n value = String(value.dropFirst().dropLast())\n }\n return value.trimmingCharacters(in: .whitespacesAndNewlines)\n }\n}\n"}, "97f9ecb2b96c9ddb97240179e9fff1300131bc37": {"t": 1785757701.6072829, "n": 1098, "h": "d8c80dd222ab4880", "c": "import Foundation\n\npublic struct DeepSeekSettingsReader: Sendable {\n public static let apiKeyEnvironmentKey = \"DEEPSEEK_API_KEY\"\n public static let apiKeyEnvironmentKeys = [Self.apiKeyEnvironmentKey, \"DEEPSEEK_KEY\"]\n\n public static func apiKey(\n environment: [String: String] = ProcessInfo.processInfo.environment) -> String?\n {\n for key in self.apiKeyEnvironmentKeys {\n guard let raw = environment[key]?.trimmingCharacters(in: .whitespacesAndNewlines),\n !raw.isEmpty\n else {\n continue\n }\n let cleaned = Self.cleaned(raw)\n if !cleaned.isEmpty {\n return cleaned\n }\n }\n return nil\n }\n\n private static func cleaned(_ raw: String) -> String {\n var value = raw\n if (value.hasPrefix(\"\\\"\") && value.hasSuffix(\"\\\"\")) ||\n (value.hasPrefix(\"'\") && value.hasSuffix(\"'\"))\n {\n value = String(value.dropFirst().dropLast())\n }\n return value.trimmingCharacters(in: .whitespacesAndNewlines)\n }\n}\n"}, "b6b77b4b8ea803b671dea666bc76135e6af0c057": {"t": 1785757702.8962462, "n": 1104, "h": "6808c8210be5c958", "c": "import Foundation\n\npublic struct DeepSeekSettingsReader: Sendable {\n public static let apiKeyEnvironmentKey = \"DEEPSEEK_API_KEY\"\n public static let apiKeyEnvironmentKeys = [Self.apiKeyEnvironmentKey, \"DEEPSEEK_KEY\"]\n\n public static func apiKey(\n environment: [String: String] = ProcessInfo.processInfo.environment) -> String?\n {\n for key in self.apiKeyEnvironmentKeys {\n guard let raw = environment[key]?.trimmingCharacters(in: .whitespacesAndNewlines),\n !raw.isEmpty\n else {\n continue\n }\n let cleaned = Self.cleaned(raw)\n if !cleaned.isEmpty {\n return cleaned\n }\n }\n return nil\n }\n\n private static func cleaned(_ raw: String) -> String {\n var value = raw\n if (value.hasPrefix(\"\\\"\") && value.hasSuffix(\"\\\"\")) ||\n (value.hasPrefix(\"'\") && value.hasSuffix(\"'\"))\n {\n value.removeFirst()\n value.removeLast()\n }\n return value.trimmingCharacters(in: .whitespacesAndNewlines)\n }\n}\n"}}, "Tests/CodexBarTests/UsageStorePathDebugTests.swift": {"e531e1c8a1aac332f8cc40b6614afc42cfd08663": {"t": 1785745903.1378713, "n": 2122, "h": "6c75bf4d490ccfb6", "c": "import CodexBarCore\nimport Foundation\nimport Testing\n@testable import CodexBar\n\n@MainActor\nstruct UsageStorePathDebugTests {\n @Test\n func `refresh path debug info populates snapshot`() async throws {\n let suite = \"UsageStorePathDebugTests-path\"\n let defaults = try #require(UserDefaults(suiteName: suite))\n defaults.removePersistentDomain(forName: suite)\n let configStore = testConfigStore(suiteName: suite)\n let settings = SettingsStore(\n userDefaults: defaults,\n configStore: configStore,\n zaiTokenStore: NoopZaiTokenStore())\n let store = UsageStore(\n fetcher: UsageFetcher(),\n browserDetection: BrowserDetection(cacheTTL: 0),\n settings: settings,\n startupBehavior: .full)\n\n let deadline = Date().addingTimeInterval(2)\n while store.pathDebugInfo == .empty, Date() < deadline {\n try? await Task.sleep(nanoseconds: 50_000_000)\n }\n\n #expect(store.pathDebugInfo != .empty)\n #expect(store.pathDebugInfo.effectivePATH.isEmpty == false)\n }\n\n @Test\n func `deepseek debug log includes selected token account`() async throws {\n let suite = \"UsageStorePathDebugTests-deepseek-debug-token-account\"\n let defaults = try #require(UserDefaults(suiteName: suite))\n defaults.removePersistentDomain(forName: suite)\n let configStore = testConfigStore(suiteName: suite)\n let settings = SettingsStore(\n userDefaults: defaults,\n configStore: configStore,\n zaiTokenStore: NoopZaiTokenStore())\n settings.addTokenAccount(provider: .deepseek, label: \"Primary\", token: \"sk-deepseek-test\")\n let store = UsageStore(\n fetcher: UsageFetcher(),\n browserDetection: BrowserDetection(cacheTTL: 0),\n settings: settings,\n startupBehavior: .testing,\n environmentBase: [:])\n\n let debugLog = await store.debugLog(for: UsageProvider.deepseek)\n\n #expect(debugLog == \"DEEPSEEK_API_KEY=present source=settings-token-account\")\n }\n}\n"}, "af375de65c67f7c0183011e63513248e8e11aacc": {"t": 1785757699.4179316, "n": 2122, "h": "6c75bf4d490ccfb6", "c": "import CodexBarCore\nimport Foundation\nimport Testing\n@testable import CodexBar\n\n@MainActor\nstruct UsageStorePathDebugTests {\n @Test\n func `refresh path debug info populates snapshot`() async throws {\n let suite = \"UsageStorePathDebugTests-path\"\n let defaults = try #require(UserDefaults(suiteName: suite))\n defaults.removePersistentDomain(forName: suite)\n let configStore = testConfigStore(suiteName: suite)\n let settings = SettingsStore(\n userDefaults: defaults,\n configStore: configStore,\n zaiTokenStore: NoopZaiTokenStore())\n let store = UsageStore(\n fetcher: UsageFetcher(),\n browserDetection: BrowserDetection(cacheTTL: 0),\n settings: settings,\n startupBehavior: .full)\n\n let deadline = Date().addingTimeInterval(2)\n while store.pathDebugInfo == .empty, Date() < deadline {\n try? await Task.sleep(nanoseconds: 50_000_000)\n }\n\n #expect(store.pathDebugInfo != .empty)\n #expect(store.pathDebugInfo.effectivePATH.isEmpty == false)\n }\n\n @Test\n func `deepseek debug log includes selected token account`() async throws {\n let suite = \"UsageStorePathDebugTests-deepseek-debug-token-account\"\n let defaults = try #require(UserDefaults(suiteName: suite))\n defaults.removePersistentDomain(forName: suite)\n let configStore = testConfigStore(suiteName: suite)\n let settings = SettingsStore(\n userDefaults: defaults,\n configStore: configStore,\n zaiTokenStore: NoopZaiTokenStore())\n settings.addTokenAccount(provider: .deepseek, label: \"Primary\", token: \"sk-deepseek-test\")\n let store = UsageStore(\n fetcher: UsageFetcher(),\n browserDetection: BrowserDetection(cacheTTL: 0),\n settings: settings,\n startupBehavior: .testing,\n environmentBase: [:])\n\n let debugLog = await store.debugLog(for: UsageProvider.deepseek)\n\n #expect(debugLog == \"DEEPSEEK_API_KEY=present source=settings-token-account\")\n }\n}\n"}, "8dfcaf7b3fe4174bb5de95bc10aee70f9c53615c": {"t": 1785757701.2221227, "n": 1111, "h": "561e2536134ef735", "c": "import CodexBarCore\nimport Foundation\nimport Testing\n@testable import CodexBar\n\n@MainActor\nstruct UsageStorePathDebugTests {\n @Test\n func `refresh path debug info populates snapshot`() async throws {\n let suite = \"UsageStorePathDebugTests-path\"\n let defaults = try #require(UserDefaults(suiteName: suite))\n defaults.removePersistentDomain(forName: suite)\n let configStore = testConfigStore(suiteName: suite)\n let settings = SettingsStore(\n userDefaults: defaults,\n configStore: configStore,\n zaiTokenStore: NoopZaiTokenStore())\n let store = UsageStore(\n fetcher: UsageFetcher(),\n browserDetection: BrowserDetection(cacheTTL: 0),\n settings: settings,\n startupBehavior: .full)\n\n let deadline = Date().addingTimeInterval(2)\n while store.pathDebugInfo == .empty, Date() < deadline {\n try? await Task.sleep(nanoseconds: 50_000_000)\n }\n\n #expect(store.pathDebugInfo != .empty)\n #expect(store.pathDebugInfo.effectivePATH.isEmpty == false)\n }\n}\n"}, "5cef4be9127069596fd362585e625d98130e15dc": {"t": 1785757703.805613, "n": 1111, "h": "76edaea28f2538b8", "c": "import CodexBarCore\nimport Foundation\nimport Testing\n@testable import CodexBar\n\n@MainActor\n@Suite\nstruct UsageStorePathDebugTests {\n @Test\n func refreshPathDebugInfoPopulatesSnapshot() async throws {\n let suite = \"UsageStorePathDebugTests-path\"\n let defaults = try #require(UserDefaults(suiteName: suite))\n defaults.removePersistentDomain(forName: suite)\n let configStore = testConfigStore(suiteName: suite)\n let settings = SettingsStore(\n userDefaults: defaults,\n configStore: configStore,\n zaiTokenStore: NoopZaiTokenStore())\n let store = UsageStore(\n fetcher: UsageFetcher(),\n browserDetection: BrowserDetection(cacheTTL: 0),\n settings: settings,\n startupBehavior: .full)\n\n let deadline = Date().addingTimeInterval(2)\n while store.pathDebugInfo == .empty, Date() < deadline {\n try? await Task.sleep(nanoseconds: 50_000_000)\n }\n\n #expect(store.pathDebugInfo != .empty)\n #expect(store.pathDebugInfo.effectivePATH.isEmpty == false)\n }\n}\n"}, "1466284b991f53025dc8701eda14609f63298385": {"t": 1785757705.7189293, "n": 1075, "h": "70ec6af0ab1b3bf4", "c": "import CodexBarCore\nimport Foundation\nimport Testing\n@testable import CodexBar\n\n@MainActor\n@Suite\nstruct UsageStorePathDebugTests {\n @Test\n func refreshPathDebugInfoPopulatesSnapshot() async throws {\n let suite = \"UsageStorePathDebugTests-path\"\n let defaults = try #require(UserDefaults(suiteName: suite))\n defaults.removePersistentDomain(forName: suite)\n let configStore = testConfigStore(suiteName: suite)\n let settings = SettingsStore(\n userDefaults: defaults,\n configStore: configStore,\n zaiTokenStore: NoopZaiTokenStore())\n let store = UsageStore(\n fetcher: UsageFetcher(),\n browserDetection: BrowserDetection(cacheTTL: 0),\n settings: settings)\n\n let deadline = Date().addingTimeInterval(2)\n while store.pathDebugInfo == .empty, Date() < deadline {\n try? await Task.sleep(nanoseconds: 50_000_000)\n }\n\n #expect(store.pathDebugInfo != .empty)\n #expect(store.pathDebugInfo.effectivePATH.isEmpty == false)\n }\n}\n"}, "72784ca5e1cb548788408fd4bc704344fb72240a": {"t": 1785757707.0789864, "n": 1055, "h": "2b7699afe8bf8ed9", "c": "import CodexBarCore\nimport Foundation\nimport Testing\n@testable import CodexBar\n\n@MainActor\n@Suite\nstruct UsageStorePathDebugTests {\n @Test\n func refreshPathDebugInfoPopulatesSnapshot() async {\n let suite = \"UsageStorePathDebugTests-path\"\n let defaults = UserDefaults(suiteName: suite)!\n defaults.removePersistentDomain(forName: suite)\n let configStore = testConfigStore(suiteName: suite)\n let settings = SettingsStore(\n userDefaults: defaults,\n configStore: configStore,\n zaiTokenStore: NoopZaiTokenStore())\n let store = UsageStore(\n fetcher: UsageFetcher(),\n browserDetection: BrowserDetection(cacheTTL: 0),\n settings: settings)\n\n let deadline = Date().addingTimeInterval(2)\n while store.pathDebugInfo == .empty, Date() < deadline {\n try? await Task.sleep(nanoseconds: 50_000_000)\n }\n\n #expect(store.pathDebugInfo != .empty)\n #expect(store.pathDebugInfo.effectivePATH.isEmpty == false)\n }\n}\n"}, "3b5628d1f6be11e8e43b00559835a3b895e12ec1": {"t": 1785757708.5244918, "n": 932, "h": "11b40d0a0d93d44a", "c": "import CodexBarCore\nimport Foundation\nimport Testing\n@testable import CodexBar\n\n@MainActor\n@Suite\nstruct UsageStorePathDebugTests {\n @Test\n func refreshPathDebugInfoPopulatesSnapshot() async {\n let suite = \"UsageStorePathDebugTests-path\"\n let defaults = UserDefaults(suiteName: suite)!\n defaults.removePersistentDomain(forName: suite)\n let settings = SettingsStore(userDefaults: defaults, zaiTokenStore: NoopZaiTokenStore())\n let store = UsageStore(\n fetcher: UsageFetcher(),\n browserDetection: BrowserDetection(cacheTTL: 0),\n settings: settings)\n\n let deadline = Date().addingTimeInterval(2)\n while store.pathDebugInfo == .empty, Date() < deadline {\n try? await Task.sleep(nanoseconds: 50_000_000)\n }\n\n #expect(store.pathDebugInfo != .empty)\n #expect(store.pathDebugInfo.effectivePATH.isEmpty == false)\n }\n}\n"}}, "Tests/CodexBarTests/DeepSeekSettingsReaderTests.swift": {"e531e1c8a1aac332f8cc40b6614afc42cfd08663": {"t": 1785745903.4830012, "n": 2287, "h": "216724ff48d27a49", "c": "import CodexBarCore\nimport Testing\n\nstruct DeepSeekSettingsReaderTests {\n @Test\n func `reads DEEPSEEK_API_KEY`() {\n let env = [\"DEEPSEEK_API_KEY\": \"sk-abc123\"]\n #expect(DeepSeekSettingsReader.apiKey(environment: env) == \"sk-abc123\")\n }\n\n @Test\n func `falls back to DEEPSEEK_KEY`() {\n let env = [\"DEEPSEEK_KEY\": \"sk-fallback\"]\n #expect(DeepSeekSettingsReader.apiKey(environment: env) == \"sk-fallback\")\n }\n\n @Test\n func `DEEPSEEK_API_KEY takes priority over DEEPSEEK_KEY`() {\n let env = [\"DEEPSEEK_API_KEY\": \"sk-primary\", \"DEEPSEEK_KEY\": \"sk-secondary\"]\n #expect(DeepSeekSettingsReader.apiKey(environment: env) == \"sk-primary\")\n }\n\n @Test\n func `trims whitespace`() {\n let env = [\"DEEPSEEK_API_KEY\": \" sk-trimmed \"]\n #expect(DeepSeekSettingsReader.apiKey(environment: env) == \"sk-trimmed\")\n }\n\n @Test\n func `strips double quotes`() {\n let env = [\"DEEPSEEK_API_KEY\": \"\\\"sk-quoted\\\"\"]\n #expect(DeepSeekSettingsReader.apiKey(environment: env) == \"sk-quoted\")\n }\n\n @Test\n func `strips single quotes`() {\n let env = [\"DEEPSEEK_KEY\": \"'sk-single'\"]\n #expect(DeepSeekSettingsReader.apiKey(environment: env) == \"sk-single\")\n }\n\n @Test\n func `returns nil when no key present`() {\n #expect(DeepSeekSettingsReader.apiKey(environment: [:]) == nil)\n }\n\n @Test\n func `returns nil for empty key`() {\n let env = [\"DEEPSEEK_API_KEY\": \"\"]\n #expect(DeepSeekSettingsReader.apiKey(environment: env) == nil)\n }\n\n @Test\n func `returns nil for whitespace-only key`() {\n let env = [\"DEEPSEEK_API_KEY\": \" \"]\n #expect(DeepSeekSettingsReader.apiKey(environment: env) == nil)\n }\n}\n\nstruct DeepSeekProviderTokenResolverTests {\n @Test\n func `resolves from environment`() {\n let env = [\"DEEPSEEK_API_KEY\": \"sk-resolve-test\"]\n let resolution = ProviderTokenResolver.deepseekResolution(environment: env)\n #expect(resolution?.token == \"sk-resolve-test\")\n #expect(resolution?.source == .environment)\n }\n\n @Test\n func `returns nil when key absent`() {\n let resolution = ProviderTokenResolver.deepseekResolution(environment: [:])\n #expect(resolution == nil)\n }\n}\n"}, "b6b77b4b8ea803b671dea666bc76135e6af0c057": {"t": 1785757701.6450808, "n": 2287, "h": "216724ff48d27a49", "c": "import CodexBarCore\nimport Testing\n\nstruct DeepSeekSettingsReaderTests {\n @Test\n func `reads DEEPSEEK_API_KEY`() {\n let env = [\"DEEPSEEK_API_KEY\": \"sk-abc123\"]\n #expect(DeepSeekSettingsReader.apiKey(environment: env) == \"sk-abc123\")\n }\n\n @Test\n func `falls back to DEEPSEEK_KEY`() {\n let env = [\"DEEPSEEK_KEY\": \"sk-fallback\"]\n #expect(DeepSeekSettingsReader.apiKey(environment: env) == \"sk-fallback\")\n }\n\n @Test\n func `DEEPSEEK_API_KEY takes priority over DEEPSEEK_KEY`() {\n let env = [\"DEEPSEEK_API_KEY\": \"sk-primary\", \"DEEPSEEK_KEY\": \"sk-secondary\"]\n #expect(DeepSeekSettingsReader.apiKey(environment: env) == \"sk-primary\")\n }\n\n @Test\n func `trims whitespace`() {\n let env = [\"DEEPSEEK_API_KEY\": \" sk-trimmed \"]\n #expect(DeepSeekSettingsReader.apiKey(environment: env) == \"sk-trimmed\")\n }\n\n @Test\n func `strips double quotes`() {\n let env = [\"DEEPSEEK_API_KEY\": \"\\\"sk-quoted\\\"\"]\n #expect(DeepSeekSettingsReader.apiKey(environment: env) == \"sk-quoted\")\n }\n\n @Test\n func `strips single quotes`() {\n let env = [\"DEEPSEEK_KEY\": \"'sk-single'\"]\n #expect(DeepSeekSettingsReader.apiKey(environment: env) == \"sk-single\")\n }\n\n @Test\n func `returns nil when no key present`() {\n #expect(DeepSeekSettingsReader.apiKey(environment: [:]) == nil)\n }\n\n @Test\n func `returns nil for empty key`() {\n let env = [\"DEEPSEEK_API_KEY\": \"\"]\n #expect(DeepSeekSettingsReader.apiKey(environment: env) == nil)\n }\n\n @Test\n func `returns nil for whitespace-only key`() {\n let env = [\"DEEPSEEK_API_KEY\": \" \"]\n #expect(DeepSeekSettingsReader.apiKey(environment: env) == nil)\n }\n}\n\nstruct DeepSeekProviderTokenResolverTests {\n @Test\n func `resolves from environment`() {\n let env = [\"DEEPSEEK_API_KEY\": \"sk-resolve-test\"]\n let resolution = ProviderTokenResolver.deepseekResolution(environment: env)\n #expect(resolution?.token == \"sk-resolve-test\")\n #expect(resolution?.source == .environment)\n }\n\n @Test\n func `returns nil when key absent`() {\n let resolution = ProviderTokenResolver.deepseekResolution(environment: [:])\n #expect(resolution == nil)\n }\n}\n"}}}}