From 8a8cc1df40f81f0198566af5bab893bb93ec33fd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 16:26:45 +0000 Subject: [PATCH 1/2] Initial plan From 226830ebfe07a58a030dff171470d679cf8c5835 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 6 Feb 2026 16:36:18 +0000 Subject: [PATCH 2/2] Show dual percentages for Gemini CLI (Antigravity) and Z.AI (5h/MCP) in both menu and CLI Co-authored-by: kargnas <1438533+kargnas@users.noreply.github.com> --- CopilotMonitor/CLI/main.swift | 40 ++++++++++++++++--- .../App/StatusBarController.swift | 15 ++++++- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/CopilotMonitor/CLI/main.swift b/CopilotMonitor/CLI/main.swift index 5e324ff..c9c0ed1 100644 --- a/CopilotMonitor/CLI/main.swift +++ b/CopilotMonitor/CLI/main.swift @@ -53,6 +53,16 @@ struct JSONFormatter { providerDict["usagePercentage"] = result.usage.usagePercentage } + // Z.AI: include both token and MCP usage percentages + if identifier == .zaiCodingPlan { + if let tokenPercent = result.details?.tokenUsagePercent { + providerDict["tokenUsagePercent"] = tokenPercent + } + if let mcpPercent = result.details?.mcpUsagePercent { + providerDict["mcpUsagePercent"] = mcpPercent + } + } + if identifier == .geminiCLI, let accounts = result.details?.geminiAccounts, !accounts.isEmpty { var accountsArray: [[String: Any]] = [] for account in accounts { @@ -61,6 +71,7 @@ struct JSONFormatter { accountDict["email"] = account.email accountDict["remainingPercentage"] = account.remainingPercentage accountDict["modelBreakdown"] = account.modelBreakdown + accountDict["authSource"] = account.authSource accountsArray.append(accountDict) } providerDict["accounts"] = accountsArray @@ -107,7 +118,7 @@ struct TableFormatter { let accounts = result.details?.geminiAccounts, accounts.count > 1 { for account in accounts { - output += formatGeminiAccountRow(account: account) + output += formatGeminiAccountRow(account: account, allResults: results) output += "\n" } } else { @@ -140,7 +151,7 @@ struct TableFormatter { let typeStr = getProviderType(result) let typePadded = typeStr.padding(toLength: columnWidths.type, withPad: " ", startingAt: 0) - let usageStr = formatUsagePercentage(result) + let usageStr = formatUsagePercentage(identifier: identifier, result: result) let usagePadded = usageStr.padding(toLength: columnWidths.usage, withPad: " ", startingAt: 0) let metricsStr = formatMetrics(result) @@ -157,22 +168,41 @@ struct TableFormatter { } } - private static func formatUsagePercentage(_ result: ProviderResult) -> String { + private static func formatUsagePercentage(identifier: ProviderIdentifier, result: ProviderResult) -> String { switch result.usage { case .payAsYouGo: // Pay-as-you-go doesn't have meaningful usage percentage - show dash return "-" case .quotaBased: + // Z.AI: show both 5h token and MCP percentages + if identifier == .zaiCodingPlan { + let percents = [result.details?.tokenUsagePercent, result.details?.mcpUsagePercent].compactMap { $0 } + if percents.count == 2 { + return percents.map { String(format: "%.0f%%", $0) }.joined(separator: ",") + } + } let percentage = result.usage.usagePercentage return String(format: "%.0f%%", percentage) } } - private static func formatGeminiAccountRow(account: GeminiAccountQuota) -> String { + private static func formatGeminiAccountRow(account: GeminiAccountQuota, allResults: [ProviderIdentifier: ProviderResult]) -> String { let accountName = "Gemini (#\(account.accountIndex + 1))" let providerPadded = accountName.padding(toLength: columnWidths.provider, withPad: " ", startingAt: 0) let typePadded = "Quota-based".padding(toLength: columnWidths.type, withPad: " ", startingAt: 0) - let usageStr = String(format: "%.0f%%", 100 - account.remainingPercentage) + let geminiUsedPercent = 100 - account.remainingPercentage + + // For Antigravity-sourced accounts, show both Gemini CLI % and Antigravity % + let usageStr: String + if account.authSource.lowercased().contains("antigravity"), + let antigravityResult = allResults[.antigravity], + case .quotaBased(let agRemaining, let agEntitlement, _) = antigravityResult.usage, + agEntitlement > 0 { + let antigravityUsedPercent = (Double(agEntitlement - agRemaining) / Double(agEntitlement)) * 100 + usageStr = String(format: "%.0f%%,%.0f%%", geminiUsedPercent, antigravityUsedPercent) + } else { + usageStr = String(format: "%.0f%%", geminiUsedPercent) + } let usagePadded = usageStr.padding(toLength: columnWidths.usage, withPad: " ", startingAt: 0) let metricsStr = "\(String(format: "%.0f", account.remainingPercentage))% remaining (\(account.email))" diff --git a/CopilotMonitor/CopilotMonitor/App/StatusBarController.swift b/CopilotMonitor/CopilotMonitor/App/StatusBarController.swift index 1047428..7c425ef 100644 --- a/CopilotMonitor/CopilotMonitor/App/StatusBarController.swift +++ b/CopilotMonitor/CopilotMonitor/App/StatusBarController.swift @@ -1041,9 +1041,22 @@ final class StatusBarController: NSObject { let sourceLabel = authSourceLabel(for: account.authSource, provider: .geminiCLI) ?? "Unknown" displayName += " (\(sourceLabel))" } + // Build percentage array for display + // For Antigravity-sourced accounts, show both Gemini CLI % and Antigravity % + // (same dual-window pattern as Codex) + let usedPercents: [Double] + if account.authSource.lowercased().contains("antigravity"), + let antigravityResult = providerResults[.antigravity], + case .quotaBased(let agRemaining, let agEntitlement, _) = antigravityResult.usage, + agEntitlement > 0 { + let antigravityUsedPercent = (Double(agEntitlement - agRemaining) / Double(agEntitlement)) * 100 + usedPercents = [usedPercent, antigravityUsedPercent] + } else { + usedPercents = [usedPercent] + } let item = createNativeQuotaMenuItem( name: displayName, - usedPercent: usedPercent, + usedPercents: usedPercents, icon: iconForProvider(.geminiCLI) ) item.tag = 999