import CodexBarMacroSupport import Foundation @ProviderDescriptorRegistration @ProviderDescriptorDefinition public enum MiniMaxProviderDescriptor { static func makeDescriptor() -> ProviderDescriptor { ProviderDescriptor( id: .minimax, metadata: ProviderMetadata( id: .minimax, displayName: "MiniMax", sessionLabel: "Prompts", weeklyLabel: "Window", opusLabel: nil, supportsOpus: false, supportsCredits: false, creditsHint: "", toggleTitle: "Show MiniMax usage", cliName: "minimax", defaultEnabled: false, isPrimaryProvider: false, usesAccountFallback: false, browserCookieOrder: ProviderBrowserCookieDefaults.defaultImportOrder, dashboardURL: "https://platform.minimax.io/user-center/payment/coding-plan?cycle_type=3", statusPageURL: nil), branding: ProviderBranding( iconStyle: .minimax, iconResourceName: "ProviderIcon-minimax", color: ProviderColor(red: 254 / 255, green: 96 / 255, blue: 60 / 255)), tokenCost: ProviderTokenCostConfig( supportsTokenCost: false, noDataMessage: { "MiniMax cost summary is not supported." }), fetchPlan: ProviderFetchPlan( sourceModes: [.auto, .web], pipeline: ProviderFetchPipeline(resolveStrategies: { _ in [MiniMaxCodingPlanFetchStrategy()] })), cli: ProviderCLIConfig( name: "minimax", aliases: ["mini-max"], versionDetector: nil)) } } struct MiniMaxCodingPlanFetchStrategy: ProviderFetchStrategy { let id: String = "minimax.web" let kind: ProviderFetchKind = .web private static let log = CodexBarLog.logger("minimax-web") func isAvailable(_ context: ProviderFetchContext) async -> Bool { if Self.resolveCookieOverride(environment: context.env) != nil { return true } #if os(macOS) return MiniMaxCookieImporter.hasSession() #else return false #endif } func fetch(_ context: ProviderFetchContext) async throws -> ProviderFetchResult { if let override = Self.resolveCookieOverride(environment: context.env) { Self.log.debug("Using MiniMax cookie header from settings/env") let snapshot = try await MiniMaxUsageFetcher.fetchUsage( cookieHeader: override.cookieHeader, authorizationToken: override.authorizationToken, groupID: override.groupID) return self.makeResult( usage: snapshot.toUsageSnapshot(), sourceLabel: "web") } #if os(macOS) let sessions = (try? MiniMaxCookieImporter.importSessions()) ?? [] guard !sessions.isEmpty else { throw MiniMaxSettingsError.missingCookie } let tokenLog: (String) -> Void = { msg in Self.log.debug(msg) } let accessTokens = MiniMaxLocalStorageImporter.importAccessTokens(logger: tokenLog) let groupIDs = MiniMaxLocalStorageImporter.importGroupIDs(logger: tokenLog) var tokensByLabel: [String: [String]] = [:] var groupIDByLabel: [String: String] = [:] for token in accessTokens { let normalized = Self.normalizeStorageLabel(token.sourceLabel) tokensByLabel[normalized, default: []].append(token.accessToken) if let groupID = token.groupID, groupIDByLabel[normalized] == nil { groupIDByLabel[normalized] = groupID } } for (label, groupID) in groupIDs { let normalized = Self.normalizeStorageLabel(label) if groupIDByLabel[normalized] == nil { groupIDByLabel[normalized] = groupID } } var lastError: Error? for session in sessions { let tokenCandidates = tokensByLabel[session.sourceLabel] ?? [] let groupID = groupIDByLabel[session.sourceLabel] let cookieToken = Self.cookieValue(named: "HERTZ-SESSION", in: session.cookieHeader) var attempts: [String?] = tokenCandidates.map(\.self) if let cookieToken, !tokenCandidates.contains(cookieToken) { attempts.append(cookieToken) } attempts.append(nil) for token in attempts { let tokenLabel: String = { guard let token else { return "" } if token == cookieToken { return " + HERTZ-SESSION bearer" } return " + access token" }() Self.log.debug("Trying MiniMax cookies from \(session.sourceLabel)\(tokenLabel)") do { let snapshot = try await MiniMaxUsageFetcher.fetchUsage( cookieHeader: session.cookieHeader, authorizationToken: token, groupID: groupID) Self.log.debug("MiniMax cookies valid from \(session.sourceLabel)") return self.makeResult( usage: snapshot.toUsageSnapshot(), sourceLabel: "web") } catch { lastError = error if Self.shouldTryNextBrowser(for: error) { if token == nil { Self.log.debug("MiniMax cookies invalid from \(session.sourceLabel), trying next browser") } continue } throw error } } } if let lastError { throw lastError } #endif throw MiniMaxSettingsError.missingCookie } func shouldFallback(on _: Error, context _: ProviderFetchContext) -> Bool { false } private static func resolveCookieOverride(environment: [String: String]) -> MiniMaxCookieOverride? { guard let raw = ProviderTokenResolver.minimaxCookie(environment: environment) else { return nil } return MiniMaxCookieHeader.override(from: raw) } private static func normalizeStorageLabel(_ label: String) -> String { let suffixes = [" (Session Storage)", " (IndexedDB)"] for suffix in suffixes where label.hasSuffix(suffix) { return String(label.dropLast(suffix.count)) } return label } private static func cookieValue(named name: String, in header: String) -> String? { let parts = header.split(separator: ";") for part in parts { let trimmed = part.trimmingCharacters(in: .whitespacesAndNewlines) guard trimmed.lowercased().hasPrefix("\(name.lowercased())=") else { continue } return String(trimmed.dropFirst(name.count + 1)) } return nil } private static func shouldTryNextBrowser(for error: Error) -> Bool { if case MiniMaxUsageError.invalidCredentials = error { return true } if case MiniMaxUsageError.parseFailed = error { return true } return false } }