713 lines · 28.9 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 refresh = "arrow.clockwise"        case dashboard = "chart.bar"        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                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(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(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)        } 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)    {        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 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))        }    }     private static func appendOpenAIAPIUsageSummary(        entries: inout [Entry],        usage: OpenAIAPIUsageSnapshot)    {        let today = usage.latestDay        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.latestDay        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 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)        guard !entries.isEmpty else { return nil }        return Section(entries: entries)    }     private static func accountEntries(        provider: UsageProvider,        snapshot: UsageSnapshot?,        metadata: ProviderMetadata,        fallback: AccountInfo,        hidePersonalInfo: Bool) -> [Entry]    {        var entries: [Entry] = []        let emailText = snapshot?.accountEmail(for: provider)?            .trimmingCharacters(in: .whitespacesAndNewlines)        let loginMethodText = snapshot?.loginMethod(for: provider)?            .trimmingCharacters(in: .whitespacesAndNewlines)        let redactedEmail = PersonalInfoRedactor.redactEmail(emailText, isEnabled: hidePersonalInfo)         if let emailText, !emailText.isEmpty {            entries.append(.text("\(L("Account")): \(redactedEmail)", .secondary))        }        if provider == .kiro {            if let plan = snapshot?.kiroUsage?.displayPlanName,               !plan.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty            {                entries.append(.text("\(L("Plan")): \(plan)", .secondary))            }            if let loginMethodText, !loginMethodText.isEmpty {                entries.append(.text("\(L("Auth")): \(loginMethodText)", .secondary))            }            if let overages = snapshot?.kiroUsage?.overagesStatus,               !overages.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty            {                entries.append(.text("\(L("Overages")): \(overages)", .secondary))            }        } else if provider == .kilo {            let kiloLogin = self.kiloLoginParts(loginMethod: loginMethodText)            if let pass = kiloLogin.pass {                entries.append(.text("\(L("Plan")): \(AccountFormatter.plan(pass, provider: provider))", .secondary))            }            for detail in kiloLogin.details {                entries.append(.text("\(L("Activity")): \(detail)", .secondary))            }        } else if let loginMethodText, !loginMethodText.isEmpty {            if provider == .openrouter || provider == .mimo,               loginMethodText.localizedCaseInsensitiveContains("balance:")            {                let balanceValue = loginMethodText                    .replacingOccurrences(                        of: #"(?i)^\s*balance:\s*"#,                        with: "",                        options: [.regularExpression])                    .trimmingCharacters(in: .whitespacesAndNewlines)                let value = balanceValue.isEmpty ? loginMethodText : balanceValue                entries.append(                    .text("\(L("Balance")): \(AccountFormatter.plan(value, provider: provider))", .secondary))            } else {                entries.append(                    .text(                        "\(L("Plan")): \(AccountFormatter.plan(loginMethodText, provider: provider))",                        .secondary))            }        }         if metadata.usesAccountFallback {            if emailText?.isEmpty ?? true, let fallbackEmail = fallback.email, !fallbackEmail.isEmpty {                let redacted = PersonalInfoRedactor.redactEmail(fallbackEmail, isEnabled: hidePersonalInfo)                entries.append(.text("\(L("Account")): \(redacted)", .secondary))            }            if loginMethodText?.isEmpty ?? true, let fallbackPlan = fallback.plan, !fallbackPlan.isEmpty {                entries.append(                    .text(                        "\(L("Plan")): \(AccountFormatter.plan(fallbackPlan, provider: provider))",                        .secondary))            }        }         return entries    }     private static func kiloLoginParts(loginMethod: String?) -> (pass: String?, details: [String]) {        guard let loginMethod else {            return (nil, [])        }        let parts = loginMethod            .components(separatedBy: "·")            .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }            .filter { !$0.isEmpty }        guard !parts.isEmpty else {            return (nil, [])        }        let first = parts[0]        if self.isKiloActivitySegment(first) {            return (nil, parts)        }        return (first, Array(parts.dropFirst()))    }     private static func isKiloActivitySegment(_ text: String) -> Bool {        let normalized = text.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()        return normalized.hasPrefix("auto top-up:")    }

Lines 1–500 of 713.