Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions CopilotMonitor/CLI/CLIProviderManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@ actor CLIProviderManager {
static let registeredProviders: [ProviderIdentifier] = [
.claude, .codex, .geminiCLI, .openRouter,
.antigravity, .openCodeZen, .kimi, .zaiCodingPlan,
.nanoGpt,
.chutes, .copilot,
.synthetic
]

// MARK: - Initialization

init() {
// Initialize all 11 providers
// 10 shared providers (no UI dependencies)
// Initialize all providers
// Shared providers (no UI dependencies)
let claudeProvider = ClaudeProvider()
let codexProvider = CodexProvider()
let geminiCLIProvider = GeminiCLIProvider()
Expand All @@ -32,6 +33,7 @@ actor CLIProviderManager {
let openCodeZenProvider = OpenCodeZenProvider()
let kimiProvider = KimiProvider()
let zaiCodingPlanProvider = ZaiCodingPlanProvider()
let nanoGptProvider = NanoGptProvider()
let chutesProvider = ChutesProvider()
let syntheticProvider = SyntheticProvider()

Expand All @@ -47,6 +49,7 @@ actor CLIProviderManager {
openCodeZenProvider,
kimiProvider,
zaiCodingPlanProvider,
nanoGptProvider,
chutesProvider,
copilotCLIProvider,
syntheticProvider
Expand Down
20 changes: 15 additions & 5 deletions CopilotMonitor/CopilotMonitor.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
A33333333333333333333333 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A44444444444444444444444 /* AppDelegate.swift */; };
A454D8C22F30544900E355E3 /* MenuBarExtraAccess in Frameworks */ = {isa = PBXBuildFile; productRef = MBA2222222222222222222222 /* MenuBarExtraAccess */; };
A454D8C42F30548900E355E3 /* ZaiCodingPlanProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A454D8C32F30548900E355E3 /* ZaiCodingPlanProvider.swift */; };
NANOGPTAPP11111111111111 /* NanoGptProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = NANOGPTFILE222222222222 /* NanoGptProvider.swift */; };
A55555555555555555555555 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A66666666666666666666666 /* Assets.xcassets */; };
AD95EBD6AE3134DF4C797577 /* ClaudeProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DDC1B4DE6B5118CE4AE8F82 /* ClaudeProvider.swift */; };
AM1111111111111111111111 /* AppMigrationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AM2222222222222222222222 /* AppMigrationHelper.swift */; };
Expand All @@ -51,6 +52,7 @@
CLIHISTORY11111111111111 /* CopilotHistoryService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B1085A77EF4A58E5B5EC71B /* CopilotHistoryService.swift */; };
CLIKIMI1111111111111111 /* KimiProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = KI2222222222222222222222 /* KimiProvider.swift */; };
CLIZAI11111111111111111 /* ZaiCodingPlanProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A454D8C32F30548900E355E3 /* ZaiCodingPlanProvider.swift */; };
NANOGPTCLI11111111111111 /* NanoGptProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = NANOGPTFILE222222222222 /* NanoGptProvider.swift */; };
CLIOPENCZEN1111111111111 /* OpenCodeZenProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = OZ2222222222222222222222 /* OpenCodeZenProvider.swift */; };
CLIOPENROUTER111111111 /* OpenRouterProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = OR2222222222222222222222 /* OpenRouterProvider.swift */; };
CLIPROVMGR11111111111111 /* CLIProviderManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CLIPROVMGR22222222222222 /* CLIProviderManager.swift */; };
Expand All @@ -64,6 +66,7 @@
KI1111111111111111111111 /* KimiProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = KI2222222222222222222222 /* KimiProvider.swift */; };
SYNTHETIC1111111111111111 /* SyntheticProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = SYNTHETIC2222222222222222 /* SyntheticProvider.swift */; };
SYNTHTEST2222222222222222 /* SyntheticProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = SYNTHTEST1111111111111111 /* SyntheticProviderTests.swift */; };
NANOGPTTESTBF1111111111 /* NanoGptProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = NANOGPTTESTFR1111111111 /* NanoGptProviderTests.swift */; };
ME1111111111111111111111 /* MenuEnums.swift in Sources */ = {isa = PBXBuildFile; fileRef = ME2222222222222222222222 /* MenuEnums.swift */; };
OC1111111111111111111111 /* OpenCodeProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = OC2222222222222222222222 /* OpenCodeProvider.swift */; };
OR1111111111111111111111 /* OpenRouterProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = OR2222222222222222222222 /* OpenRouterProvider.swift */; };
Expand Down Expand Up @@ -142,6 +145,7 @@
9B1085A77EF4A58E5B5EC71B /* CopilotHistoryService.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CopilotHistoryService.swift; sourceTree = "<group>"; };
A44444444444444444444444 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
A454D8C32F30548900E355E3 /* ZaiCodingPlanProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZaiCodingPlanProvider.swift; sourceTree = "<group>"; };
NANOGPTFILE222222222222 /* NanoGptProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NanoGptProvider.swift; sourceTree = "<group>"; };
A66666666666666666666666 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
A77777777777777777777777 /* OpenCode Bar.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "OpenCode Bar.app"; sourceTree = BUILT_PRODUCTS_DIR; };
A88888888888888888888888 /* CopilotMonitor.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CopilotMonitor.entitlements; sourceTree = "<group>"; };
Expand Down Expand Up @@ -182,6 +186,7 @@
TAAAAAAAAAAAAAAAAAAAAAAA /* gemini_response.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = gemini_response.json; sourceTree = "<group>"; };
SYNTHETIC2222222222222222 /* SyntheticProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyntheticProvider.swift; sourceTree = "<group>"; };
SYNTHTEST1111111111111111 /* SyntheticProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyntheticProviderTests.swift; sourceTree = "<group>"; };
NANOGPTTESTFR1111111111 /* NanoGptProviderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NanoGptProviderTests.swift; sourceTree = "<group>"; };
TDDDDDDDDDDDDDDDDDDDDDD /* CopilotMonitorTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CopilotMonitorTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -233,6 +238,7 @@
isa = PBXGroup;
children = (
A454D8C32F30548900E355E3 /* ZaiCodingPlanProvider.swift */,
NANOGPTFILE222222222222 /* NanoGptProvider.swift */,
06EC3B683EB6892E4F9C8316 /* GeminiCLIProvider.swift */,
4DDC1B4DE6B5118CE4AE8F82 /* ClaudeProvider.swift */,
76783C44AA2329AE3FA7E981 /* CodexProvider.swift */,
Expand Down Expand Up @@ -388,6 +394,7 @@
C8493409A9188CFF5B73D5B3 /* MenuDesignTokenTests.swift */,
54353FD130DDE0500F6B367F /* MenuResultBuilderTests.swift */,
SYNTHTEST1111111111111111 /* SyntheticProviderTests.swift */,
NANOGPTTESTFR1111111111 /* NanoGptProviderTests.swift */,
);
path = CopilotMonitorTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -552,6 +559,7 @@
CLIOPENCZEN1111111111111 /* OpenCodeZenProvider.swift in Sources */,
CLIKIMI1111111111111111 /* KimiProvider.swift in Sources */,
CLIZAI11111111111111111 /* ZaiCodingPlanProvider.swift in Sources */,
NANOGPTCLI11111111111111 /* NanoGptProvider.swift in Sources */,
283349022F313176004DADE1 /* ChutesProvider.swift in Sources */,
CLISYNTHETIC1111111111111 /* SyntheticProvider.swift in Sources */,
CLIPROVMGR11111111111111 /* CLIProviderManager.swift in Sources */,
Expand All @@ -567,8 +575,9 @@
283348F92F313096004DADE1 /* ProviderResult.swift in Sources */,
A33333333333333333333333 /* AppDelegate.swift in Sources */,
AM1111111111111111111111 /* AppMigrationHelper.swift in Sources */,
A454D8C42F30548900E355E3 /* ZaiCodingPlanProvider.swift in Sources */,
BCDE4599B74AF7A799CE1D /* StatusBarIconView.swift in Sources */,
A454D8C42F30548900E355E3 /* ZaiCodingPlanProvider.swift in Sources */,
NANOGPTAPP11111111111111 /* NanoGptProvider.swift in Sources */,
BCDE4599B74AF7A799CE1D /* StatusBarIconView.swift in Sources */,
ME1111111111111111111111 /* MenuEnums.swift in Sources */,
D11111111111111111111111 /* StatusBarController.swift in Sources */,
E11111111111111111111111 /* CopilotUsage.swift in Sources */,
Expand Down Expand Up @@ -612,9 +621,10 @@
OR4444444444444444444444 /* OpenRouterProviderTests.swift in Sources */,
668B6906C95903D51823808A /* DependencyTests.swift in Sources */,
A1BED4A5CA1FEC2DADC461C2 /* MenuDesignTokenTests.swift in Sources */,
B58BAD3BFD97973070A2A892 /* MenuResultBuilderTests.swift in Sources */,
SYNTHTEST2222222222222222 /* SyntheticProviderTests.swift in Sources */,
);
B58BAD3BFD97973070A2A892 /* MenuResultBuilderTests.swift in Sources */,
SYNTHTEST2222222222222222 /* SyntheticProviderTests.swift in Sources */,
NANOGPTTESTBF1111111111 /* NanoGptProviderTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
Expand Down
9 changes: 9 additions & 0 deletions CopilotMonitor/CopilotMonitor/App/StatusBarController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,7 @@
.kimi,
.codex,
.zaiCodingPlan,
.nanoGpt,
.antigravity,
.chutes,
.synthetic
Expand Down Expand Up @@ -1040,6 +1041,9 @@
} else if identifier == .zaiCodingPlan {
let percents = [account.details?.tokenUsagePercent, account.details?.mcpUsagePercent].compactMap { $0 }
usedPercents = percents.isEmpty ? [account.usage.usagePercentage] : percents
} else if identifier == .nanoGpt {
let percents = [account.details?.tokenUsagePercent, account.details?.mcpUsagePercent].compactMap { $0 }
usedPercents = percents.isEmpty ? [account.usage.usagePercentage] : percents
} else {
usedPercents = [account.usage.usagePercentage]
}
Expand Down Expand Up @@ -1090,6 +1094,9 @@
} else if identifier == .zaiCodingPlan {
let percents = [result.details?.tokenUsagePercent, result.details?.mcpUsagePercent].compactMap { $0 }
usedPercents = percents.isEmpty ? [singlePercent] : percents
} else if identifier == .nanoGpt {
let percents = [result.details?.tokenUsagePercent, result.details?.mcpUsagePercent].compactMap { $0 }
usedPercents = percents.isEmpty ? [singlePercent] : percents
} else {
usedPercents = [singlePercent]
}
Expand Down Expand Up @@ -1486,6 +1493,8 @@
image = NSImage(systemSymbolName: identifier.iconName, accessibilityDescription: identifier.displayName)
case .zaiCodingPlan:
image = NSImage(named: "ZaiIcon")
case .nanoGpt:
image = NSImage(named: "NanoGptIcon")
case .synthetic:
image = NSImage(named: "SyntheticIcon")
case .chutes:
Expand Down Expand Up @@ -2114,7 +2123,7 @@
// 3. OpenRouter - only has current cost, no daily history
// We'll include today's cost if available
if let routerResult = providerResults[.openRouter],
case .payAsYouGo(_, let cost, _) = routerResult.usage,

Check warning on line 2126 in CopilotMonitor/CopilotMonitor/App/StatusBarController.swift

View workflow job for this annotation

GitHub Actions / Build & Test

immutable value 'cost' was never used; consider replacing with '_' or removing it

Check warning on line 2126 in CopilotMonitor/CopilotMonitor/App/StatusBarController.swift

View workflow job for this annotation

GitHub Actions / Build & Test

immutable value 'cost' was never used; consider replacing with '_' or removing it
let dailyCost = routerResult.details?.dailyUsage {
let today = Calendar.current.startOfDay(for: Date())
if aggregatedDailyCosts[today] == nil {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"images" : [
{
"filename" : "nano-gpt-logo.png",
"idiom" : "universal",
"scale" : "1x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "template"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
53 changes: 53 additions & 0 deletions CopilotMonitor/CopilotMonitor/Helpers/ProviderMenuBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,59 @@ extension StatusBarController {
// === Subscription ===
addSubscriptionItems(to: submenu, provider: .zaiCodingPlan, accountId: accountId)

case .nanoGpt:
if let dailyUsage = details.tokenUsagePercent {
let rows = createUsageWindowRow(
label: "Daily",
usagePercent: dailyUsage,
resetDate: details.tokenUsageReset,
windowHours: 24
)
rows.forEach { submenu.addItem($0) }
}
if let dailyUsed = details.tokenUsageUsed,
let dailyTotal = details.tokenUsageTotal {
let item = createLimitRow(label: "Daily Units", used: Double(dailyUsed), total: Double(dailyTotal))
submenu.addItem(item)
}

if details.tokenUsagePercent != nil, details.mcpUsagePercent != nil {
submenu.addItem(NSMenuItem.separator())
}

if let monthlyUsage = details.mcpUsagePercent {
let rows = createUsageWindowRow(
label: "Monthly",
usagePercent: monthlyUsage,
resetDate: details.mcpUsageReset,
isMonthly: true
)
rows.forEach { submenu.addItem($0) }
}
if let monthlyUsed = details.mcpUsageUsed,
let monthlyTotal = details.mcpUsageTotal {
let item = createLimitRow(label: "Monthly Units", used: Double(monthlyUsed), total: Double(monthlyTotal))
submenu.addItem(item)
}

if details.creditsBalance != nil || details.totalCredits != nil {
submenu.addItem(NSMenuItem.separator())
}

if let usdBalance = details.creditsBalance {
let item = NSMenuItem()
item.view = createDisabledLabelView(text: String(format: "USD Balance: $%.2f", usdBalance))
submenu.addItem(item)
}

if let nanoBalance = details.totalCredits {
let item = NSMenuItem()
item.view = createDisabledLabelView(text: String(format: "NANO Balance: %.8f", nanoBalance))
submenu.addItem(item)
}

addSubscriptionItems(to: submenu, provider: .nanoGpt, accountId: accountId)

case .chutes:
if let daily = details.dailyUsage,
let limit = details.limit {
Expand Down
5 changes: 5 additions & 0 deletions CopilotMonitor/CopilotMonitor/Models/ProviderProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ enum ProviderIdentifier: String, CaseIterable {
case openCodeZen = "opencode_zen"
case kimi
case zaiCodingPlan = "zai_coding_plan"
case nanoGpt = "nano_gpt"
case synthetic
case chutes

Expand All @@ -45,6 +46,8 @@ enum ProviderIdentifier: String, CaseIterable {
return "Kimi for Coding"
case .zaiCodingPlan:
return "Z.AI Coding Plan"
case .nanoGpt:
return "Nano-GPT"
case .synthetic:
return "Synthetic"
case .chutes:
Expand Down Expand Up @@ -74,6 +77,8 @@ enum ProviderIdentifier: String, CaseIterable {
return "k.circle"
case .zaiCodingPlan:
return "globe"
case .nanoGpt:
return "NanoGptIcon"
case .synthetic:
return "SyntheticIcon"
case .chutes:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ struct ProviderSubscriptionPresets {
SubscriptionPreset(name: "Pro", cost: 60)
]

static let nanoGpt: [SubscriptionPreset] = [
SubscriptionPreset(name: "Subscription", cost: 8)
]

static let openRouter: [SubscriptionPreset] = []
static let openCode: [SubscriptionPreset] = []
static let openCodeZen: [SubscriptionPreset] = []
Expand All @@ -177,6 +181,8 @@ struct ProviderSubscriptionPresets {
return openCodeZen
case .zaiCodingPlan:
return zaiCodingPlan
case .nanoGpt:
return nanoGpt
case .synthetic:
return synthetic
case .chutes:
Expand Down
Loading
Loading