827 lines · 34.5 KB · Swift
RawDownload
import CodexBarCoreimport Foundation @MainActorstruct MenuDescriptor {    struct SubmenuItem: Equatable {        let title: String        let action: MenuAction?        let isEnabled: Bool        let isChecked: Bool         init(title: String, action: MenuAction?, isEnabled: Bool = true, isChecked: Bool = false) {            self.title = title            self.action = action            self.isEnabled = isEnabled            self.isChecked = isChecked        }    }     struct Section {        var entries: [Entry]    }     enum Entry {        case text(String, TextStyle)        case action(String, MenuAction)        case submenu(String, String?, [SubmenuItem])        case divider    }     enum MenuActionSystemImage: String {        case installUpdate = "arrow.down.circle"        case refresh = "arrow.clockwise"        case dashboard = "chart.xyaxis.line"        case statusPage = "waveform.path.ecg"        case changelog = "list.bullet.rectangle"        case addAccount = "plus"        case systemAccount = "person.crop.circle"        case switchAccount = "key"        case openTerminal = "terminal"        case loginToProvider = "arrow.right.square"        case settings = "gearshape"        case about = "info.circle"        case quit = "xmark.rectangle"        case copyError = "doc.on.doc"    }     enum TextStyle {        case headline        case primary        case secondary    }     enum MenuAction: Equatable {        case installUpdate        case refresh        case refreshAugmentSession        case dashboard        case statusPage        case changelog        case addCodexAccount        case requestCodexSystemPromotion(UUID)        case addProviderAccount(UsageProvider)        case switchAccount(UsageProvider)        case openTerminal(command: String)        case loginToProvider(url: String)        case settings        case about        case quit        case copyError(String)    }     var sections: [Section]     static func build(        provider: UsageProvider?,        store: UsageStore,        settings: SettingsStore,        account: AccountInfo,        managedCodexAccountCoordinator: ManagedCodexAccountCoordinator? = nil,        codexAccountPromotionCoordinator: CodexAccountPromotionCoordinator? = nil,        updateReady: Bool,        includeContextualActions: Bool = true) -> MenuDescriptor    {        var sections: [Section] = []         if let provider {            let fallbackAccount = store.accountInfo(for: provider)            sections.append(Self.usageSection(for: provider, store: store, settings: settings))            if let accountSection = Self.accountSection(                for: provider,                store: store,                settings: settings,                account: fallbackAccount)            {                sections.append(accountSection)            }        } else {            var addedUsage = false             for enabledProvider in store.enabledProviders() {                sections.append(Self.usageSection(for: enabledProvider, store: store, settings: settings))                addedUsage = true            }            if addedUsage {                if let accountProvider = Self.accountProviderForCombined(store: store),                   let fallbackAccount = Optional(store.accountInfo(for: accountProvider)),                   let accountSection = Self.accountSection(                       for: accountProvider,                       store: store,                       settings: settings,                       account: fallbackAccount)                {                    sections.append(accountSection)                }            } else {                sections.append(Section(entries: [.text(L("No usage configured."), .secondary)]))            }        }         if includeContextualActions {            let actions = Self.actionsSection(                for: provider,                store: store,                account: account,                managedCodexAccountCoordinator: managedCodexAccountCoordinator,                codexAccountPromotionCoordinator: codexAccountPromotionCoordinator)            if !actions.entries.isEmpty {                sections.append(actions)            }        }        sections.append(Self.metaSection(updateReady: updateReady))         return MenuDescriptor(sections: sections)    }     private static func usageSection(        for provider: UsageProvider,        store: UsageStore,        settings: SettingsStore) -> Section    {        let meta = store.metadata(for: provider)        var entries: [Entry] = []        let headlineText: String = {            if let ver = Self.versionNumber(for: provider, store: store) { return "\(meta.displayName) \(ver)" }            return meta.displayName        }()        entries.append(.text(headlineText, .headline))         if let snap = store.snapshot(for: provider) {            let resetStyle = settings.resetTimeDisplayStyle            let labels = Self.rateWindowLabels(provider: provider, metadata: meta, snapshot: snap)            if let primary = snap.primary {                let primaryDetail = primary.resetDescription?.trimmingCharacters(in: .whitespacesAndNewlines)                let primaryDescriptionIsDetail = provider == .warp || provider == .kilo || provider == .abacus ||                    provider == .deepseek || provider == .azureopenai || provider == .mimo || provider == .qoder                let primaryWindow = if primaryDescriptionIsDetail {                    // Some providers use resetDescription for non-reset detail                    // (e.g., "Unlimited", "X/Y credits"). Avoid rendering it as a "Resets ..." line.                    RateWindow(                        usedPercent: primary.usedPercent,                        windowMinutes: primary.windowMinutes,                        resetsAt: primary.resetsAt,                        resetDescription: nil)                } else {                    primary                }                Self.appendRateWindow(                    entries: &entries,                    title: labels.primary,                    window: primaryWindow,                    resetStyle: resetStyle,                    showUsed: settings.usageBarsShowUsed)                if primaryDescriptionIsDetail,                   let primaryDetail,                   !primaryDetail.isEmpty                {                    entries.append(.text(primaryDetail, .secondary))                }                if provider == .crof,                   primary.resetsAt != nil,                   let detail = primary.resetDescription?.trimmingCharacters(in: .whitespacesAndNewlines),                   !detail.isEmpty                {                    entries.append(.text(detail, .secondary))                }                if provider == .abacus,                   let pace = store.weeklyPace(provider: provider, window: primary)                {                    let paceSummary = UsagePaceText.weeklySummary(provider: provider, pace: pace)                    entries.append(.text(paceSummary, .secondary))                }                if let paceSummary = UsagePaceText.sessionSummary(provider: provider, window: primary) {                    entries.append(.text(paceSummary, .secondary))                }            }            if let weekly = snap.secondary {                let weeklyResetOverride: String? = {                    guard provider == .warp || provider == .kilo || provider == .perplexity || provider == .crof                    else { return nil }                    let detail = weekly.resetDescription?.trimmingCharacters(in: .whitespacesAndNewlines)                    guard let detail, !detail.isEmpty else { return nil }                    if provider == .kilo, weekly.resetsAt != nil {                        return nil                    }                    return detail                }()                Self.appendRateWindow(                    entries: &entries,                    title: labels.secondary,                    window: weekly,                    resetStyle: resetStyle,                    showUsed: settings.usageBarsShowUsed,                    resetOverride: weeklyResetOverride)                if provider == .kilo,                   weekly.resetsAt != nil,                   let detail = weekly.resetDescription?.trimmingCharacters(in: .whitespacesAndNewlines),                   !detail.isEmpty                {                    entries.append(.text(detail, .secondary))                }                if let pace = store.weeklyPace(provider: provider, window: weekly) {                    let paceSummary = UsagePaceText.weeklySummary(provider: provider, pace: pace)                    entries.append(.text(paceSummary, .secondary))                }            }            if labels.showsTertiary, let opus = snap.tertiary {                // Perplexity purchased credits don't reset; show the balance as plain text.                let opusResetOverride: String? = provider == .perplexity                    ? opus.resetDescription?.trimmingCharacters(in: .whitespacesAndNewlines)                    : nil                Self.appendRateWindow(                    entries: &entries,                    title: labels.tertiary,                    window: opus,                    resetStyle: resetStyle,                    showUsed: settings.usageBarsShowUsed,                    resetOverride: opusResetOverride)            }             Self.appendProviderUsageSummaries(                entries: &entries,                snapshot: snap,                showOptionalUsage: settings.showOptionalCreditsAndExtraUsage)            if snap.rateLimitsUnavailable(for: provider) {                entries.append(.text(L("Limits not available"), .secondary))            }        } else if !store.isStale(provider: provider),                  store.knownLimitsAvailability(for: provider)?.isUnavailable == true        {            entries.append(.text(L("Limits not available"), .secondary))        } else {            entries.append(.text(L("No usage yet"), .secondary))        }         let usageContext = ProviderMenuUsageContext(            provider: provider,            store: store,            settings: settings,            metadata: meta,            snapshot: store.snapshot(for: provider))        ProviderCatalog.implementation(for: provider)?            .appendUsageMenuEntries(context: usageContext, entries: &entries)         return Section(entries: entries)    }     private static func appendProviderUsageSummaries(        entries: inout [Entry],        snapshot: UsageSnapshot,        showOptionalUsage: Bool)    {        if let cost = snapshot.providerCost {            if cost.currencyCode == "Quota" {                let used = String(format: "%.0f", cost.used)                let limit = String(format: "%.0f", cost.limit)                entries.append(.text("\(L("Quota")): \(used) / \(limit)", .primary))            }        }        if let openAIAPIUsage = snapshot.openAIAPIUsage {            Self.appendOpenAIAPIUsageSummary(entries: &entries, usage: openAIAPIUsage)        }        if let claudeAdminAPIUsage = snapshot.claudeAdminAPIUsage {            Self.appendClaudeAdminAPIUsageSummary(entries: &entries, usage: claudeAdminAPIUsage)        }        if let openRouterUsage = snapshot.openRouterUsage {            Self.appendOpenRouterUsageSummary(entries: &entries, usage: openRouterUsage)        }        if let clawRouterUsage = snapshot.clawRouterUsage {            entries.append(.text(                "\(UsageFormatter.tokenCountString(clawRouterUsage.requestCount)) \(L("requests")) · " +                    "\(UsageFormatter.tokenCountString(clawRouterUsage.totalTokens)) \(L("tokens"))",                .secondary))            if !clawRouterUsage.providers.isEmpty {                let mix = clawRouterUsage.providers.prefix(5)                    .map { "\($0.provider): \(UsageFormatter.tokenCountString($0.requestCount))" }                    .joined(separator: " · ")                entries.append(.text("Routed providers: \(mix)", .secondary))            }        }        if let poeUsage = snapshot.poeUsage, !poeUsage.daily.isEmpty {            Self.appendPoeUsageSummary(entries: &entries, usage: poeUsage)        }        if let mistralUsage = snapshot.mistralUsage, !mistralUsage.daily.isEmpty {            Self.appendMistralUsageSummary(entries: &entries, usage: mistralUsage)        }        if let mimoUsage = snapshot.mimoUsage {            entries.append(.text("\(L("Balance")): \(mimoUsage.balanceDetail)", .primary))        }        // Sakana pay-as-you-go is optional data gated by "Show optional credits and extra usage".        // Gate the render on the setting too, not just the fetch: toggling the setting off only        // rebuilds the menu, it does not immediately refetch, so a previously-populated        // sakanaPayAsYouGo would otherwise linger in the cached snapshot until the next refresh.        if showOptionalUsage, let sakanaPayAsYouGo = snapshot.sakanaPayAsYouGo {            entries.append(.text("\(L("Balance")): \(sakanaPayAsYouGo.balanceDetail)", .primary))            if let periodUsageTotal = sakanaPayAsYouGo.periodUsageTotal {                entries.append(.text(                    "\(L("Usage")): \(UsageFormatter.usdString(periodUsageTotal))",                    .secondary))            }        }    }     private static func appendOpenAIAPIUsageSummary(        entries: inout [Entry],        usage: OpenAIAPIUsageSnapshot)    {        let today = usage.currentDay        let last7 = usage.last7Days        let last30 = usage.last30Days        let historyLabel = usage.historyWindowLabel         entries.append(.text(            "\(L("Today")): \(UsageFormatter.usdString(today.costUSD)) · " +                "\(UsageFormatter.tokenCountString(today.totalTokens)) \(L("tokens"))",            .secondary))        entries.append(.text(            "7d: \(UsageFormatter.usdString(last7.costUSD)) · " +                "\(UsageFormatter.tokenCountString(last7.requests)) \(L("requests"))",            .secondary))        entries.append(.text(            "\(historyLabel): \(UsageFormatter.usdString(last30.costUSD)) · " +                "\(UsageFormatter.tokenCountString(last30.requests)) \(L("requests"))",            .secondary))        if let topModel = usage.topModels.first?.name {            entries.append(.text("\(L("Top model")): \(topModel)", .secondary))        }    }     private static func appendClaudeAdminAPIUsageSummary(        entries: inout [Entry],        usage: ClaudeAdminAPIUsageSnapshot)    {        let today = usage.currentDay        let last7 = usage.last7Days        let last30 = usage.last30Days         entries.append(.text(            "\(L("Today")): \(UsageFormatter.usdString(today.costUSD)) · " +                "\(UsageFormatter.tokenCountString(today.totalTokens)) \(L("tokens"))",            .secondary))        entries.append(.text(            "7d: \(UsageFormatter.usdString(last7.costUSD)) · " +                "\(UsageFormatter.tokenCountString(last7.totalTokens)) \(L("tokens"))",            .secondary))        entries.append(.text(            "30d: \(UsageFormatter.usdString(last30.costUSD)) · " +                "\(UsageFormatter.tokenCountString(last30.totalTokens)) \(L("tokens"))",            .secondary))        if let topModel = usage.topModels.first?.name {            entries.append(.text("\(L("Top model")): \(topModel)", .secondary))        }    }     private static func appendOpenRouterUsageSummary(        entries: inout [Entry],        usage: OpenRouterUsageSnapshot)    {        if let daily = usage.keyUsageDaily {            entries.append(.text("\(L("Today")): \(UsageFormatter.usdString(daily))", .secondary))        }        if let weekly = usage.keyUsageWeekly {            entries.append(.text("\(L("Week")): \(UsageFormatter.usdString(weekly))", .secondary))        }        if let monthly = usage.keyUsageMonthly {            entries.append(.text("\(L("Month")): \(UsageFormatter.usdString(monthly))", .secondary))        }    }     private static func appendMistralUsageSummary(        entries: inout [Entry],        usage: MistralUsageSnapshot)    {        let latest = usage.daily.last        if let latest {            entries.append(.text(                "\(L("Latest")): \(usage.currencySymbol)\(String(format: "%.4f", max(0, latest.cost))) · " +                    "\(UsageFormatter.tokenCountString(latest.totalTokens)) \(L("tokens"))",                .secondary))        }        let totalTokens = usage.totalInputTokens + usage.totalCachedTokens + usage.totalOutputTokens        entries.append(.text(            "\(L("Month")): \(usage.currencySymbol)\(String(format: "%.4f", max(0, usage.totalCost))) · " +                "\(UsageFormatter.tokenCountString(totalTokens)) \(L("tokens"))",            .secondary))        if let top = Self.topMistralModel(from: usage.daily) {            entries.append(.text("\(L("Top model")): \(top)", .secondary))        }    }     private static func topMistralModel(from entries: [MistralDailyUsageBucket]) -> String? {        var tokens: [String: Int] = [:]        for entry in entries {            for model in entry.models {                tokens[model.name, default: 0] += model.totalTokens            }        }        return tokens.max {            if $0.value == $1.value { return $0.key > $1.key }            return $0.value < $1.value        }?.key    }     private static func appendPoeUsageSummary(        entries: inout [Entry],        usage: PoeUsageHistorySnapshot)    {        let today = usage.currentDay()        let week = usage.last7Days        let month = usage.last30Days        let todayCostSuffix = today.costUSD.map { " · \(UsageFormatter.usdString($0))" } ?? ""        let weekCostSuffix = week.costUSD.map { " · \(UsageFormatter.usdString($0))" } ?? ""        let monthCostSuffix = month.costUSD.map { " · \(UsageFormatter.usdString($0))" } ?? ""        entries.append(.text(            "\(L("Today")): \(Self.pointsString(today.points)) · " +                "\(UsageFormatter.tokenCountString(today.requests)) \(L("requests"))\(todayCostSuffix)",            .secondary))        entries.append(.text(            "7d: \(Self.pointsString(week.points)) · " +                "\(UsageFormatter.tokenCountString(week.requests)) \(L("requests"))\(weekCostSuffix)",            .secondary))        entries.append(.text(            "30d: \(Self.pointsString(month.points)) · " +                "\(UsageFormatter.tokenCountString(month.requests)) \(L("requests"))\(monthCostSuffix)",            .secondary))        if let topModel = usage.topModels.first {            entries.append(                .text(                    "\(L("Top model")): \(topModel.name) (\(Self.pointsString(topModel.points)))",                    .secondary))        }        if !usage.topUsageTypes.isEmpty {            let summary = usage.topUsageTypes                .prefix(2)                .map { "\($0.name): \(Self.pointsString($0.points))" }                .joined(separator: " · ")            entries.append(.text("Usage mix: \(summary)", .secondary))        }        let recent = usage.recentEntries(limit: 3)        if !recent.isEmpty {            entries.append(.text("Recent activity:", .secondary))            for entry in recent {                let stamp = Self.poeTimeString(entry.createdAt)                entries.append(.text(                    "\(stamp) · \(entry.model) · \(Self.pointsString(entry.points))",                    .secondary))            }        }    }     private static func pointsString(_ points: Double) -> String {        let value = max(0, points)        if value.rounded() == value {            return "\(UsageFormatter.tokenCountString(Int(value))) points"        }        return "\(String(format: "%.1f", value)) points"    }     private static func poeTimeString(_ date: Date) -> String {        let formatter = DateFormatter()        formatter.locale = Locale(identifier: "en_US_POSIX")        formatter.timeZone = .current        formatter.dateFormat = "MM-dd HH:mm"        return formatter.string(from: date)    }     private static func accountSection(        for provider: UsageProvider,        store: UsageStore,        settings: SettingsStore,        account: AccountInfo) -> Section?    {        let snapshot = store.snapshot(for: provider)        let metadata = store.metadata(for: provider)        let entries = Self.accountEntries(            provider: provider,            snapshot: snapshot,            metadata: metadata,            fallback: account,            hidePersonalInfo: settings.hidePersonalInfo)

Lines 1–500 of 827.