889 lines · 34.3 KB · Swift
RawDownload
import AppKitimport CodexBarCore extension StatusItemController {    /// Identifies which manual refresh a task belongs to, so per-provider refreshes stay independent    /// of each other and of the all-providers refresh.    enum ManualRefreshScope: Hashable {        case global        case provider(UsageProvider)    }} enum LoginNotificationLogic {    static func notificationCopy(providerName: String) -> (title: String, body: String) {        (            L("login_success_notification_title", providerName),            L("login_success_notification_body"))    }} extension StatusItemController: StatusItemMenuPersistentActionDelegate {    // MARK: - Actions reachable from menus     func refreshStore(        forceTokenUsage: Bool,        refreshOpenMenusWhenComplete: Bool = true,        interaction: ProviderInteraction = .userInitiated)    {        Task {            await self.performStoreRefresh(                forceTokenUsage: forceTokenUsage,                refreshOpenMenusWhenComplete: refreshOpenMenusWhenComplete,                interaction: interaction)        }    }     func performStoreRefresh(        forceTokenUsage: Bool,        refreshOpenMenusWhenComplete: Bool,        interaction: ProviderInteraction) async    {        await self.withProviderInteraction(interaction) {            await self.store.refresh(forceTokenUsage: forceTokenUsage)            guard !Task.isCancelled, !self.hasPreparedForAppShutdown else { return }            self.store.scheduleStorageFootprintRefreshForOverview(force: true)            if refreshOpenMenusWhenComplete {                self.refreshOpenMenusAfterExplicitStoreAction()            } else {                self.invalidateMenus()            }        }    }     func performStoreRefresh(        enrichmentMode: UsageStore.RefreshEnrichmentMode,        refreshOpenMenusWhenComplete: Bool,        interaction: ProviderInteraction) async    {        await self.withProviderInteraction(interaction) {            await self.store.refresh(enrichmentMode: enrichmentMode)            guard !Task.isCancelled, !self.hasPreparedForAppShutdown else { return }            self.store.scheduleStorageFootprintRefreshForOverview(force: true)            if refreshOpenMenusWhenComplete {                self.refreshOpenMenusAfterExplicitStoreAction()            } else {                self.invalidateMenus()            }        }    }     func performStoreRefresh(        for provider: UsageProvider,        refreshOpenMenusWhenComplete: Bool,        interaction: ProviderInteraction) async    {        await self.withProviderInteraction(interaction) {            await self.store.awaitForcedRefreshEnrichment()            guard !Task.isCancelled, !self.hasPreparedForAppShutdown else { return }            let refreshStartedAt = Date()            await self.store.refreshProvider(provider)            guard !Task.isCancelled, !self.hasPreparedForAppShutdown else { return }            await self.store.refreshProviderStatus(provider)            guard !Task.isCancelled, !self.hasPreparedForAppShutdown else { return }            await self.store.refreshTokenUsageNow(for: provider, force: true)            guard !Task.isCancelled, !self.hasPreparedForAppShutdown else { return }            if provider == .codex {                await self.store.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)                guard !Task.isCancelled, !self.hasPreparedForAppShutdown else { return }                await self.store.refreshOpenAIDashboardIfNeeded(                    force: true,                    expectedGuard: self.store.freshCodexOpenAIWebRefreshGuard(),                    bypassCoalescing: true)                guard !Task.isCancelled, !self.hasPreparedForAppShutdown else { return }                if self.store.openAIDashboardRequiresLogin {                    await self.store.refreshProvider(.codex)                    guard !Task.isCancelled, !self.hasPreparedForAppShutdown else { return }                    await self.store.refreshCreditsNow(minimumSnapshotUpdatedAt: refreshStartedAt)                    guard !Task.isCancelled, !self.hasPreparedForAppShutdown else { return }                }            }            self.store.scheduleStorageFootprintRefresh(for: [provider], force: true)            self.store.persistWidgetSnapshot(reason: "provider-refresh")            if refreshOpenMenusWhenComplete {                self.refreshOpenMenusAfterExplicitStoreAction()            } else {                self.invalidateMenus()            }        }    }     private func withProviderInteraction(        _ interaction: ProviderInteraction,        operation: () async -> Void) async    {        if interaction == .userInitiated {            await BrowserCookieAccessGate.withExplicitRetry {                await ProviderInteractionContext.$current.withValue(interaction) {                    await operation()                }            }        } else {            await ProviderInteractionContext.$current.withValue(interaction) {                await operation()            }        }    }     func refreshOpenMenusAfterExplicitStoreAction() {        self.invalidateMenus(            refreshOpenMenus: true,            deferOpenParentMenuRebuild: true)    }     @objc func refreshNow() {        self.startManualRefresh(            for: nil,            originatingMenuID: nil,            originatingMenuInteractionGeneration: nil)    }     @objc func refreshMenuItem(_ sender: NSMenuItem) {        self.refreshMenuProviderNow(in: sender.menu)    }     func refreshMenuProviderNow(in menu: NSMenu?) {        let originatingMenuID = menu.map(ObjectIdentifier.init)        let originatingMenuInteractionGeneration = originatingMenuID.flatMap {            self.menuSession.menuInteractionGeneration(for: $0)        }        self.startManualRefresh(            for: self.manualRefreshProvider(for: menu),            originatingMenuID: originatingMenuID,            originatingMenuInteractionGeneration: originatingMenuInteractionGeneration)    }     private func refreshMenuProviderNow(        menuID: ObjectIdentifier,        originatingMenuInteractionGeneration: Int)    {        let menu = self.openMenus[menuID] ?? self.mergedMenu.flatMap {            ObjectIdentifier($0) == menuID ? $0 : nil        }        let provider = menu.flatMap { self.manualRefreshProvider(for: $0) } ?? self.menuProviders[menuID]        self.startManualRefresh(            for: provider,            originatingMenuID: menuID,            originatingMenuInteractionGeneration: originatingMenuInteractionGeneration)    }     private func startManualRefresh(        for provider: UsageProvider?,        originatingMenuID: ObjectIdentifier?,        originatingMenuInteractionGeneration: Int?)    {        let scope: ManualRefreshScope = provider.map(ManualRefreshScope.provider) ?? .global        let scopedRefreshInFlight = provider.map { self.store.refreshingProviders.contains($0) }            ?? !self.store.refreshingProviders.isEmpty        // Two different providers may refresh concurrently, but an all-providers (.global) refresh must        // not overlap a per-provider one (or vice versa) — that would duplicate the shared fetch work.        let conflictsWithOtherScope = scope == .global            ? self.manualRefreshTasks.contains { $0.key != .global }            : self.manualRefreshTasks[.global] != nil        guard !self.hasPreparedForAppShutdown,              self.manualRefreshTasks[scope] == nil,              !conflictsWithOtherScope,              !self.store.hasForcedRefreshEnrichmentInFlight,              !self.store.isRefreshing,              !scopedRefreshInFlight        else { return }         let frozenModels = self.frozenManualRefreshMenuCardModels()        let viewportRestoreRequests = self.armManualRefreshViewportRestoreRequests(            originatingMenuID: originatingMenuID,            originatingMenuInteractionGeneration: originatingMenuInteractionGeneration)        let task = Task { @MainActor [weak self] in            guard let self else { return }            var completed = false            defer {                self.manualRefreshTasks[scope] = nil                self.menuCardRefreshMonitor.endManualRefresh(for: provider)                self.updatePersistentRefreshItemsEnabled()                if completed {                    self.scheduleCompletedManualRefreshViewportRestore(viewportRestoreRequests)                } else {                    self.cancelManualRefreshViewportRestoreRequests(viewportRestoreRequests)                }                self.completeParentMenuRebuildAfterHostedSubviewCloseIfNeeded()                self.prepareAttachedClosedMenusIfNeeded()            }            guard !Task.isCancelled, !self.hasPreparedForAppShutdown else { return }            #if DEBUG            if let operation = self._test_manualRefreshOperation {                await operation()                guard !Task.isCancelled, !self.hasPreparedForAppShutdown else { return }                completed = true                return            }            #endif            if let provider {                await self.performStoreRefresh(                    for: provider,                    refreshOpenMenusWhenComplete: true,                    interaction: .userInitiated)            } else {                await self.performStoreRefresh(                    enrichmentMode: .forcedBackground,                    refreshOpenMenusWhenComplete: true,                    interaction: .userInitiated)            }            guard !Task.isCancelled, !self.hasPreparedForAppShutdown else { return }            completed = true        }        self.manualRefreshTasks[scope] = task        self.menuCardRefreshMonitor.beginManualRefresh(frozenModels: frozenModels, provider: provider)        self.updatePersistentRefreshItemsEnabled()    }     private func manualRefreshProvider(for menu: NSMenu?) -> UsageProvider? {        guard let menu else { return nil }        if self.shouldMergeIcons {            guard self.mergedMenu == nil || menu === self.mergedMenu else { return nil }            guard !self.isMergedOverviewSelected(in: menu) else { return nil }            return self.resolvedMenuProvider()        }        return self.menuProviders[ObjectIdentifier(menu)]    }     private func frozenManualRefreshMenuCardModels() -> [UsageProvider: UsageMenuCardView.Model] {        var providers = self.store.enabledProvidersForDisplay()        if let lastMenuProvider,           !providers.contains(lastMenuProvider)        {            providers.append(lastMenuProvider)        }        if providers.isEmpty,           let defaultProvider = self.settings.orderedProviders().first ?? UsageProvider.allCases.first        {            providers.append(defaultProvider)        }         var models: [UsageProvider: UsageMenuCardView.Model] = [:]        for provider in providers {            models[provider] = self.menuCardModel(for: provider)        }        return models    }     func performPersistentRefreshAction(in menuID: ObjectIdentifier) {        guard let menuInteractionGeneration = self.menuSession.menuInteractionGeneration(for: menuID) else { return }        self.performPersistentRefreshAction(            in: menuID,            menuInteractionGeneration: menuInteractionGeneration)    }     nonisolated func performPersistentRefreshAction(        in menuID: ObjectIdentifier,        menuInteractionGeneration: Int)    {        Task { @MainActor [weak self] in            guard let self else { return }            self.refreshMenuProviderNow(                menuID: menuID,                originatingMenuInteractionGeneration: menuInteractionGeneration)        }    }     nonisolated func performPersistentSettingsAction() {        Task { @MainActor [weak self] in            guard let self else { return }            self.closeOpenMenusFromShortcutIfNeeded()            self.showSettingsGeneral()        }    }     nonisolated func performPersistentQuitAction() {        Task { @MainActor [weak self] in            guard let self else { return }            self.closeOpenMenusFromShortcutIfNeeded()            self.quit()        }    }     nonisolated func performProviderNavigation(_ direction: StatusItemMenuProviderNavigationDirection) {        Task { @MainActor [weak self] in            self?.navigateProviderSwitcher(direction)        }    }     @objc func refreshAugmentSession() {        Task {            await self.store.forceRefreshAugmentSession()            // Also trigger a full refresh to update the menu and clear any stale errors            await ProviderInteractionContext.$current.withValue(.userInitiated) {                await self.store.refresh(forceTokenUsage: false)            }            self.refreshOpenMenusAfterExplicitStoreAction()        }    }     @objc func installUpdate() {        self.updater.installUpdate()    }     @objc func openDashboard() {        let preferred = self.lastMenuProvider            ?? (self.store.isEnabled(.codex) ? .codex : self.store.enabledProviders().first)         let provider = preferred ?? .codex        guard let url = self.dashboardURL(for: provider) else { return }        NSWorkspace.shared.open(url)    }     func dashboardURL(        for provider: UsageProvider,        environment: [String: String] = ProcessInfo.processInfo.environment) -> URL?    {        if provider == .alibaba {            return self.settings.alibabaCodingPlanAPIRegion.dashboardURL        }        if provider == .alibabatokenplan {            return AlibabaTokenPlanUsageFetcher.dashboardURL(                region: self.settings.alibabaTokenPlanAPIRegion,                environment: environment)        }        if provider == .minimax {            return self.settings.minimaxAPIRegion.dashboardURL        }         if provider == .opencodego {            return self.settings.opencodegoDashboardURL        }         if provider == .wayfinder {            return WayfinderProviderImplementation.dashboardURL(                settings: self.settings,                environment: environment)        }         if provider == .zai {            return ZaiUsageFetcher.resolveDashboardURL(                region: self.settings.zaiAPIRegion,                environment: environment,                usageScope: self.settings.zaiEffectiveUsageScope())        }         if provider == .qoder {            return QoderProviderDescriptor.dashboardURL(                settings: self.settings.qoderSettingsSnapshot(tokenOverride: nil),                sourceLabel: self.store.sourceLabel(for: .qoder))        }         let meta = self.store.metadata(for: provider)        let urlString: String? = if provider == .claude, self.store.isClaudeSubscription() {            meta.subscriptionDashboardURL ?? meta.dashboardURL        } else {            meta.dashboardURL        }         guard let urlString else { return nil }        return URL(string: urlString)    }     @objc func openCreditsPurchase() {        let preferred = self.lastMenuProvider            ?? (self.store.isEnabled(.codex) ? .codex : self.store.enabledProviders().first)        let provider = preferred ?? .codex        guard provider == .codex else { return }         let dashboardURL = self.store.metadata(for: .codex).dashboardURL        let purchaseURL = Self.sanitizedCreditsPurchaseURL(self.store.openAIDashboard?.creditsPurchaseURL)        let urlString = purchaseURL ?? dashboardURL        guard let urlString,              let url = URL(string: urlString) else { return }         let autoStart = true        let accountEmail = self.store.codexAccountEmailForOpenAIDashboard()        let cacheScope = self.store.codexCookieCacheScopeForOpenAIWeb()        guard OpenAICreditsPurchaseWindowController.canOpenPurchaseWindow(            accountEmail: accountEmail,            cacheScope: cacheScope)        else {            self.creditsPurchaseWindow?.close()            self.creditsPurchaseWindow = nil            return        }        let controller = self.creditsPurchaseWindow ?? OpenAICreditsPurchaseWindowController()        controller.show(            purchaseURL: url,            accountEmail: accountEmail,            cacheScope: cacheScope,            autoStartPurchase: autoStart)        self.creditsPurchaseWindow = controller    }     static func sanitizedCreditsPurchaseURL(_ raw: String?) -> String? {        guard let raw, let url = URL(string: raw) else { return nil }        guard Self.isAllowedChatGPTPurchaseHost(url) else { return nil }        let pathComponents = url.pathComponents.map { $0.lowercased() }        let allowed = ["settings", "usage", "billing", "credits"]        guard pathComponents.contains(where: { allowed.contains($0) }) else { return nil }        var components = URLComponents(url: url, resolvingAgainstBaseURL: false)        components?.query = nil        components?.fragment = nil        return components?.url?.absoluteString ?? url.absoluteString    }     private static func isAllowedChatGPTPurchaseHost(_ url: URL) -> Bool {        guard url.scheme?.lowercased() == "https" else { return false }        guard let host = url.host?.lowercased() else { return false }        return host == "chatgpt.com" || host.hasSuffix(".chatgpt.com")    }     @objc func openStatusPage() {        let preferred = self.lastMenuProvider            ?? (self.store.isEnabled(.codex) ? .codex : self.store.enabledProviders().first)         self.openStatusPage(for: preferred ?? .codex)    }     @objc func openStatusPageFromMenuItem(_ sender: NSMenuItem) {        let provider = (sender.identifier?.rawValue).flatMap(UsageProvider.init(rawValue:))            ?? self.lastMenuProvider            ?? .codex        self.openStatusPage(for: provider)    }     private func openStatusPage(for provider: UsageProvider) {        let meta = self.store.metadata(for: provider)        let urlString = meta.statusPageURL ?? meta.statusLinkURL        guard let urlString, let url = URL(string: urlString) else { return }        NSWorkspace.shared.open(url)    }     @objc func openChangelog() {        let preferred = self.lastMenuProvider            ?? (self.store.isEnabled(.codex) ? .codex : self.store.enabledProviders().first)         let provider = preferred ?? .codex        let meta = self.store.metadata(for: provider)        guard let urlString = meta.changelogURL, let url = URL(string: urlString) else { return }        NSWorkspace.shared.open(url)    }     @objc func openTerminalCommand(_ sender: NSMenuItem) {        let command = sender.representedObject as? String ?? "claude"        self.openTerminal(command: command)    }     @objc func openLoginToProvider(_ sender: NSMenuItem) {        guard let urlString = sender.representedObject as? String,              let url = URL(string: urlString) else { return }        NSWorkspace.shared.open(url)    }     @objc func addManagedCodexAccountFromMenu(_: NSMenuItem) {        guard self.codexAccountPromotionCoordinator.isInteractionBlocked() == false else {            self.loginLogger.info("Add Account tap ignored: Codex account change already in-flight")            return        }        guard self.settings.hasUnreadableManagedCodexAccountStore == false else {            self.presentLoginAlert(                title: L("Managed Codex accounts unavailable"),                message: L(                    "CodexBar could not read managed account storage. " +                        "Recover the store before adding another account."))            return        }         Task { @MainActor [weak self] in            guard let self else { return }            do {                let account = try await self.managedCodexAccountCoordinator.authenticateManagedAccount()                self.settings.selectAuthenticatedManagedCodexAccount(account)                await ProviderInteractionContext.$current.withValue(.userInitiated) {                    await self.store.refreshCodexAccountScopedState(allowDisabled: true)                }            } catch {                self.presentManagedCodexAccountError(error)            }        }

Lines 1–500 of 889.