@sriinnu/runic 1.2.0 → 2.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +267 -0
- package/LICENSE +373 -21
- package/README.md +98 -84
- package/THIRD-PARTY-NOTICES.md +651 -0
- package/package.json +14 -4
- package/.swiftformat +0 -50
- package/.swiftlint.yml +0 -160
- package/CONTRIBUTING.md +0 -456
- package/Icon.icns +0 -0
- package/Icon.icon/Assets/runic.png +0 -0
- package/Icon.icon/icon.json +0 -36
- package/Package.resolved +0 -51
- package/Package.swift +0 -136
- package/Packages/Helix/LICENSE +0 -21
- package/Packages/Helix/Package.swift +0 -29
- package/Packages/Helix/README.md +0 -976
- package/Packages/Helix/Sources/Helix/Binding.swift +0 -111
- package/Packages/Helix/Sources/Helix/CommandParser.swift +0 -160
- package/Packages/Helix/Sources/Helix/CommandSignature.swift +0 -117
- package/Packages/Helix/Sources/Helix/ExpressibleFromArgument.swift +0 -72
- package/Packages/Helix/Sources/Helix/HelpGenerator.swift +0 -175
- package/Packages/Helix/Sources/Helix/NameSpecification.swift +0 -98
- package/Packages/Helix/Sources/Helix/ParsableCommand.swift +0 -204
- package/Packages/Helix/Sources/Helix/Platform/DarwinPlatformContext.swift +0 -44
- package/Packages/Helix/Sources/Helix/Platform/LinuxPlatformContext.swift +0 -34
- package/Packages/Helix/Sources/Helix/Platform/PlatformContext+Default.swift +0 -91
- package/Packages/Helix/Sources/Helix/Platform/PlatformContext.swift +0 -94
- package/Packages/Helix/Sources/Helix/Platform/PlatformPath.swift +0 -167
- package/Packages/Helix/Sources/Helix/Platform/Stdio.swift +0 -99
- package/Packages/Helix/Sources/Helix/Platform/WebPlatformContext.swift +0 -146
- package/Packages/Helix/Sources/Helix/Platform/WindowsPlatformContext.swift +0 -97
- package/Packages/Helix/Sources/Helix/Program.swift +0 -204
- package/Packages/Helix/Sources/Helix/PropertyWrappers.swift +0 -367
- package/Packages/Silo/LICENSE +0 -21
- package/Packages/Silo/Package.swift +0 -34
- package/Packages/Silo/README.md +0 -466
- package/Packages/Silo/Sources/Silo/BinaryCookiesReader.swift +0 -169
- package/Packages/Silo/Sources/Silo/BrowserCookieAnalytics.swift +0 -365
- package/Packages/Silo/Sources/Silo/BrowserCookieBackends.swift +0 -594
- package/Packages/Silo/Sources/Silo/BrowserCookieClient.swift +0 -326
- package/Packages/Silo/Sources/Silo/BrowserCookieExport.swift +0 -154
- package/Packages/Silo/Sources/Silo/BrowserCookieImport.swift +0 -119
- package/Packages/Silo/Sources/Silo/BrowserCookieMockStore.swift +0 -121
- package/Packages/Silo/Sources/Silo/BrowserCookieModels.swift +0 -391
- package/Packages/Silo/Sources/Silo/ChromiumCookieReader.swift +0 -240
- package/Packages/Silo/Sources/Silo/CryptoSupport.swift +0 -86
- package/Packages/Silo/Sources/Silo/FirefoxCookieReader.swift +0 -172
- package/Packages/Silo/Sources/Silo/LinuxChromiumCookieReader.swift +0 -172
- package/Packages/Silo/Sources/Silo/LinuxSecretService.swift +0 -105
- package/Packages/Silo/Sources/Silo/MacOSChromiumCookieReader.swift +0 -191
- package/Packages/Silo/Sources/Silo/SQLiteSnapshot.swift +0 -41
- package/Packages/Silo/Sources/Silo/WindowsChromiumCookieReader.swift +0 -110
- package/RuniciOS/App/RuniciOSApp.swift +0 -105
- package/RuniciOS/Core/iOSUsageStore.swift +0 -192
- package/RuniciOS/Views/ProviderDetailView.swift +0 -312
- package/RuniciOS/Views/ProviderListView.swift +0 -228
- package/RuniciOS/Widgets/LargeWidget.swift +0 -367
- package/RuniciOS/Widgets/LiveActivity.swift +0 -342
- package/RuniciOS/Widgets/LockScreenWidget.swift +0 -273
- package/RuniciOS/Widgets/MediumWidget.swift +0 -370
- package/RuniciOS/Widgets/RunicWidget.swift +0 -274
- package/RuniciOS/Widgets/SmallWidget.swift +0 -281
- package/RuniciOS/Widgets/WidgetModels.swift +0 -285
- package/RuniciOS/Widgets/WidgetTimeline.swift +0 -270
- package/Scripts/CREATION-SUMMARY.md +0 -367
- package/Scripts/DIRECTORY-STRUCTURE.md +0 -358
- package/Scripts/GETTING-STARTED-CHECKLIST.md +0 -364
- package/Scripts/INDEX.md +0 -365
- package/Scripts/QUICK-REFERENCE.md +0 -164
- package/Scripts/README-SCRIPTS.md +0 -926
- package/Scripts/build-android.sh +0 -526
- package/Scripts/build-ios.sh +0 -529
- package/Scripts/build-macos.sh +0 -603
- package/Scripts/build-windows.sh +0 -504
- package/Scripts/build_icon.sh +0 -49
- package/Scripts/changelog-to-html.sh +0 -89
- package/Scripts/check-release-assets.sh +0 -10
- package/Scripts/ci-config.yml +0 -474
- package/Scripts/compile_and_run.sh +0 -219
- package/Scripts/compile_and_run_adhoc.sh +0 -4
- package/Scripts/docs-list.mjs +0 -119
- package/Scripts/make_appcast.sh +0 -58
- package/Scripts/package_app.sh +0 -409
- package/Scripts/release-lib.sh +0 -214
- package/Scripts/release.sh +0 -76
- package/Scripts/setup-all.sh +0 -387
- package/Scripts/setup-ios.sh +0 -404
- package/Scripts/setup-react-native.sh +0 -523
- package/Scripts/sign-and-notarize.sh +0 -122
- package/Scripts/test_live_update.sh +0 -38
- package/Scripts/validate_changelog.sh +0 -23
- package/Scripts/verify_appcast.sh +0 -92
- package/Sources/Runic/About.swift +0 -93
- package/Sources/Runic/AppNotifications.swift +0 -115
- package/Sources/Runic/Controllers/StatusItemController+Actions.swift +0 -666
- package/Sources/Runic/Controllers/StatusItemController+Animation.swift +0 -518
- package/Sources/Runic/Controllers/StatusItemController+ChartSubmenus.swift +0 -810
- package/Sources/Runic/Controllers/StatusItemController+CustomProviders.swift +0 -87
- package/Sources/Runic/Controllers/StatusItemController+Menu.swift +0 -1407
- package/Sources/Runic/Controllers/StatusItemController+MenuCards.swift +0 -337
- package/Sources/Runic/Controllers/StatusItemController+MenuHelpers.swift +0 -395
- package/Sources/Runic/Controllers/StatusItemController.swift +0 -360
- package/Sources/Runic/Core/BudgetNotificationManager.swift +0 -80
- package/Sources/Runic/Core/Login/ClaudeLoginRunner.swift +0 -103
- package/Sources/Runic/Core/Login/CodexLoginRunner.swift +0 -154
- package/Sources/Runic/Core/Login/CursorLoginRunner.swift +0 -206
- package/Sources/Runic/Core/Login/GeminiLoginRunner.swift +0 -92
- package/Sources/Runic/Core/Rendering/IconRenderer.swift +0 -1216
- package/Sources/Runic/Core/Rendering/IconView.swift +0 -120
- package/Sources/Runic/Core/Rendering/ProviderBrandIcon.swift +0 -71
- package/Sources/Runic/Core/RunicAnimation.swift +0 -53
- package/Sources/Runic/Core/RunicColors.swift +0 -73
- package/Sources/Runic/Core/RunicCornerRadius.swift +0 -15
- package/Sources/Runic/Core/RunicSpacing.swift +0 -68
- package/Sources/Runic/Core/Stores/AuggieTokenStore.swift +0 -119
- package/Sources/Runic/Core/Stores/AzureOpenAITokenStore.swift +0 -119
- package/Sources/Runic/Core/Stores/CerebrasTokenStore.swift +0 -119
- package/Sources/Runic/Core/Stores/CohereTokenStore.swift +0 -119
- package/Sources/Runic/Core/Stores/CopilotTokenStore.swift +0 -119
- package/Sources/Runic/Core/Stores/CustomProviderStore.swift +0 -158
- package/Sources/Runic/Core/Stores/DeepSeekTokenStore.swift +0 -119
- package/Sources/Runic/Core/Stores/FireworksTokenStore.swift +0 -119
- package/Sources/Runic/Core/Stores/GroqTokenStore.swift +0 -119
- package/Sources/Runic/Core/Stores/KimiTokenStore.swift +0 -119
- package/Sources/Runic/Core/Stores/MiniMaxCookieHeaderStore.swift +0 -119
- package/Sources/Runic/Core/Stores/MiniMaxGroupIDStore.swift +0 -119
- package/Sources/Runic/Core/Stores/MiniMaxTokenStore.swift +0 -119
- package/Sources/Runic/Core/Stores/MistralTokenStore.swift +0 -119
- package/Sources/Runic/Core/Stores/OpenRouterTokenStore.swift +0 -119
- package/Sources/Runic/Core/Stores/PerplexityTokenStore.swift +0 -119
- package/Sources/Runic/Core/Stores/ProviderToggleStore.swift +0 -30
- package/Sources/Runic/Core/Stores/QwenTokenStore.swift +0 -119
- package/Sources/Runic/Core/Stores/SambaNovaTokenStore.swift +0 -119
- package/Sources/Runic/Core/Stores/SettingsStore.swift +0 -1711
- package/Sources/Runic/Core/Stores/TogetherTokenStore.swift +0 -119
- package/Sources/Runic/Core/Stores/UsageStore+Accessors.swift +0 -20
- package/Sources/Runic/Core/Stores/UsageStore+Status.swift +0 -189
- package/Sources/Runic/Core/Stores/UsageStore+TokenCost.swift +0 -33
- package/Sources/Runic/Core/Stores/UsageStore+WidgetSnapshot.swift +0 -67
- package/Sources/Runic/Core/Stores/UsageStore.swift +0 -3605
- package/Sources/Runic/Core/Stores/XAITokenStore.swift +0 -119
- package/Sources/Runic/Core/Stores/ZaiTokenStore.swift +0 -118
- package/Sources/Runic/Core/UsageExporter.swift +0 -193
- package/Sources/Runic/Date+RelativeDescription.swift +0 -21
- package/Sources/Runic/HiddenWindowView.swift +0 -32
- package/Sources/Runic/InstallOrigin.swift +0 -9
- package/Sources/Runic/KeyboardShortcuts+Names.swift +0 -6
- package/Sources/Runic/MouseLocationReader.swift +0 -65
- package/Sources/Runic/Notifications+Runic.swift +0 -6
- package/Sources/Runic/OpenAICreditsPurchaseWindowController.swift +0 -503
- package/Sources/Runic/ProviderRegistry.swift +0 -100
- package/Sources/Runic/ProviderSwitcherButtons.swift +0 -267
- package/Sources/Runic/Providers/Antigravity/AntigravityLoginFlow.swift +0 -11
- package/Sources/Runic/Providers/Antigravity/AntigravityProviderImplementation.swift +0 -14
- package/Sources/Runic/Providers/Auggie/AuggieProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/Azure/AzureProviderImplementation.swift +0 -52
- package/Sources/Runic/Providers/Bedrock/BedrockProviderImplementation.swift +0 -42
- package/Sources/Runic/Providers/Cerebras/CerebrasProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/Claude/ClaudeLoginFlow.swift +0 -26
- package/Sources/Runic/Providers/Claude/ClaudeProviderImplementation.swift +0 -14
- package/Sources/Runic/Providers/Codex/CodexLoginFlow.swift +0 -18
- package/Sources/Runic/Providers/Codex/CodexProviderImplementation.swift +0 -15
- package/Sources/Runic/Providers/Cohere/CohereProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/Copilot/CopilotLoginFlow.swift +0 -193
- package/Sources/Runic/Providers/Copilot/CopilotProviderImplementation.swift +0 -110
- package/Sources/Runic/Providers/Cursor/CursorLoginFlow.swift +0 -28
- package/Sources/Runic/Providers/Cursor/CursorProviderImplementation.swift +0 -15
- package/Sources/Runic/Providers/DeepSeek/DeepSeekProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/Factory/FactoryLoginFlow.swift +0 -12
- package/Sources/Runic/Providers/Factory/FactoryProviderImplementation.swift +0 -15
- package/Sources/Runic/Providers/Fireworks/FireworksProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/Gemini/GeminiLoginFlow.swift +0 -20
- package/Sources/Runic/Providers/Gemini/GeminiProviderImplementation.swift +0 -15
- package/Sources/Runic/Providers/Groq/GroqProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/Kimi/KimiProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/MiniMax/MiniMaxProviderImplementation.swift +0 -32
- package/Sources/Runic/Providers/Mistral/MistralProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/OpenRouter/OpenRouterProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/Perplexity/PerplexityProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/SambaNova/SambaNovaProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/Shared/ProviderCatalog.swift +0 -15
- package/Sources/Runic/Providers/Shared/ProviderImplementation.swift +0 -48
- package/Sources/Runic/Providers/Shared/ProviderImplementationRegistry.swift +0 -66
- package/Sources/Runic/Providers/Shared/ProviderLoginFlow.swift +0 -12
- package/Sources/Runic/Providers/Shared/ProviderSettingsDescriptors.swift +0 -99
- package/Sources/Runic/Providers/Shared/SystemSettingsLinks.swift +0 -18
- package/Sources/Runic/Providers/Together/TogetherProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/XAI/XAIProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/Zai/ZaiProviderImplementation.swift +0 -24
- package/Sources/Runic/Resources/ProviderIcon-antigravity.svg +0 -2
- package/Sources/Runic/Resources/ProviderIcon-auggie.svg +0 -3
- package/Sources/Runic/Resources/ProviderIcon-azure.svg +0 -5
- package/Sources/Runic/Resources/ProviderIcon-bedrock.svg +0 -7
- package/Sources/Runic/Resources/ProviderIcon-cerebras.svg +0 -3
- package/Sources/Runic/Resources/ProviderIcon-claude.svg +0 -1
- package/Sources/Runic/Resources/ProviderIcon-codex.svg +0 -1
- package/Sources/Runic/Resources/ProviderIcon-cohere.svg +0 -3
- package/Sources/Runic/Resources/ProviderIcon-copilot.svg +0 -1
- package/Sources/Runic/Resources/ProviderIcon-cursor.svg +0 -3
- package/Sources/Runic/Resources/ProviderIcon-deepseek.svg +0 -4
- package/Sources/Runic/Resources/ProviderIcon-factory.svg +0 -3
- package/Sources/Runic/Resources/ProviderIcon-fireworks.svg +0 -3
- package/Sources/Runic/Resources/ProviderIcon-gemini.svg +0 -1
- package/Sources/Runic/Resources/ProviderIcon-groq.svg +0 -1
- package/Sources/Runic/Resources/ProviderIcon-kimi.svg +0 -4
- package/Sources/Runic/Resources/ProviderIcon-minimax.svg +0 -1
- package/Sources/Runic/Resources/ProviderIcon-mistral.svg +0 -5
- package/Sources/Runic/Resources/ProviderIcon-openrouter.svg +0 -7
- package/Sources/Runic/Resources/ProviderIcon-perplexity.svg +0 -4
- package/Sources/Runic/Resources/ProviderIcon-qwen.svg +0 -9
- package/Sources/Runic/Resources/ProviderIcon-sambanova.svg +0 -4
- package/Sources/Runic/Resources/ProviderIcon-together.svg +0 -5
- package/Sources/Runic/Resources/ProviderIcon-vertexai.svg +0 -17
- package/Sources/Runic/Resources/ProviderIcon-xai.svg +0 -3
- package/Sources/Runic/Resources/ProviderIcon-zai.svg +0 -5
- package/Sources/Runic/Resources/RunicMenubarIcon.svg +0 -7
- package/Sources/Runic/Resources/provider-context-windows.json +0 -20
- package/Sources/Runic/RunicApp.swift +0 -357
- package/Sources/Runic/SessionQuotaNotifications.swift +0 -58
- package/Sources/Runic/UsagePaceText.swift +0 -52
- package/Sources/Runic/UsageProgressBar.swift +0 -224
- package/Sources/Runic/Utilities/DisplayLink.swift +0 -96
- package/Sources/Runic/Utilities/LoadingPattern.swift +0 -60
- package/Sources/Runic/Utilities/PerformanceConstants.swift +0 -85
- package/Sources/Runic/Views/Menu/AlertsMenuView.swift +0 -256
- package/Sources/Runic/Views/Menu/ChartPanelStyle.swift +0 -22
- package/Sources/Runic/Views/Menu/CostComparativeChartMenuView.swift +0 -275
- package/Sources/Runic/Views/Menu/CostHistoryChartMenuView.swift +0 -377
- package/Sources/Runic/Views/Menu/CreditsHistoryChartMenuView.swift +0 -312
- package/Sources/Runic/Views/Menu/EfficiencyMetricsMenuView.swift +0 -312
- package/Sources/Runic/Views/Menu/HeroStatCardsMenuView.swift +0 -228
- package/Sources/Runic/Views/Menu/HourlyActivityChartMenuView.swift +0 -228
- package/Sources/Runic/Views/Menu/InlineUsageChartView.swift +0 -155
- package/Sources/Runic/Views/Menu/MenuCardEntranceModifier.swift +0 -64
- package/Sources/Runic/Views/Menu/MenuCardSidebarView.swift +0 -268
- package/Sources/Runic/Views/Menu/MenuCardSkeletonView.swift +0 -104
- package/Sources/Runic/Views/Menu/MenuCardView.swift +0 -1900
- package/Sources/Runic/Views/Menu/MenuContent.swift +0 -150
- package/Sources/Runic/Views/Menu/MenuDescriptor.swift +0 -369
- package/Sources/Runic/Views/Menu/MenuHighlightStyle.swift +0 -42
- package/Sources/Runic/Views/Menu/ModelBreakdownMenuView.swift +0 -235
- package/Sources/Runic/Views/Menu/OverviewMenuView.swift +0 -278
- package/Sources/Runic/Views/Menu/ProjectBreakdownMenuView.swift +0 -209
- package/Sources/Runic/Views/Menu/ProjectBudgetMenuView.swift +0 -220
- package/Sources/Runic/Views/Menu/ProviderTabBarView.swift +0 -88
- package/Sources/Runic/Views/Menu/SubscriptionUtilizationChartMenuView.swift +0 -201
- package/Sources/Runic/Views/Menu/UsageBreakdownChartMenuView.swift +0 -398
- package/Sources/Runic/Views/Menu/UsageHeatmapMenuView.swift +0 -232
- package/Sources/Runic/Views/Menu/UsageTimelineChartMenuView.swift +0 -364
- package/Sources/Runic/Views/Menu/UsageWindowComparisonChartMenuView.swift +0 -190
- package/Sources/Runic/Views/Menu/WeeklyActivityChartMenuView.swift +0 -132
- package/Sources/Runic/Views/Performance/PerformanceDashboardView.swift +0 -618
- package/Sources/Runic/Views/Preferences/LiquidComponents.swift +0 -305
- package/Sources/Runic/Views/Preferences/PreferencesAboutPane.swift +0 -271
- package/Sources/Runic/Views/Preferences/PreferencesAdvancedPane.swift +0 -268
- package/Sources/Runic/Views/Preferences/PreferencesAlertsPane.swift +0 -422
- package/Sources/Runic/Views/Preferences/PreferencesAnalyticsPane.swift +0 -641
- package/Sources/Runic/Views/Preferences/PreferencesBudgetsPane.swift +0 -344
- package/Sources/Runic/Views/Preferences/PreferencesComponents.swift +0 -230
- package/Sources/Runic/Views/Preferences/PreferencesCustomProvidersPane.swift +0 -322
- package/Sources/Runic/Views/Preferences/PreferencesDebugPane.swift +0 -469
- package/Sources/Runic/Views/Preferences/PreferencesGeneralPane.swift +0 -231
- package/Sources/Runic/Views/Preferences/PreferencesHelpPane.swift +0 -50
- package/Sources/Runic/Views/Preferences/PreferencesIntegrationsPane.swift +0 -567
- package/Sources/Runic/Views/Preferences/PreferencesPerformancePane.swift +0 -288
- package/Sources/Runic/Views/Preferences/PreferencesProvidersPane.swift +0 -3435
- package/Sources/Runic/Views/Preferences/PreferencesSelection.swift +0 -25
- package/Sources/Runic/Views/Preferences/PreferencesSyncPane.swift +0 -59
- package/Sources/Runic/Views/Preferences/PreferencesView.swift +0 -206
- package/Sources/Runic/Views/Rating/QualityRatingView.swift +0 -238
- package/Sources/Runic/Views/Team/TeamDashboardView.swift +0 -371
- package/Sources/Runic/Views/Team/TeamInviteSheet.swift +0 -175
- package/Sources/Runic/Views/Team/TeamManagementView.swift +0 -761
- package/Sources/Runic/Views/Team/TeamMemberRow.swift +0 -181
- package/Sources/RunicCLI/CLIEntry.swift +0 -942
- package/Sources/RunicCLI/CLIRenderer.swift +0 -87
- package/Sources/RunicCLI/Commands/EnhancedUsageCommand.swift +0 -588
- package/Sources/RunicCLI/Commands/ModelsCommand.swift +0 -362
- package/Sources/RunicCLI/Commands/ProjectsCommand.swift +0 -439
- package/Sources/RunicCLI/Commands/ResetCommand.swift +0 -429
- package/Sources/RunicCLI/Commands/UsageLedgerSourceFactory.swift +0 -168
- package/Sources/RunicClaudeWatchdog/main.swift +0 -122
- package/Sources/RunicClaudeWebProbe/main.swift +0 -62
- package/Sources/RunicCore/AlertRuleStore.swift +0 -187
- package/Sources/RunicCore/BrowserCookieImportOrder.swift +0 -25
- package/Sources/RunicCore/CopilotUsageModels.swift +0 -84
- package/Sources/RunicCore/CostUsageFetcher.swift +0 -119
- package/Sources/RunicCore/CostUsageModels.swift +0 -479
- package/Sources/RunicCore/CreditsModels.swift +0 -50
- package/Sources/RunicCore/CustomProviders/CustomProviderModels.swift +0 -269
- package/Sources/RunicCore/CustomProviders/GenericProviderFetcher.swift +0 -633
- package/Sources/RunicCore/CustomProviders/ProviderTemplates.swift +0 -500
- package/Sources/RunicCore/Host/PTY/TTYCommandRunner.swift +0 -679
- package/Sources/RunicCore/Host/Process/SubprocessRunner.swift +0 -135
- package/Sources/RunicCore/Integrations/GitHubIntegration.swift +0 -173
- package/Sources/RunicCore/Logging/JSONStderrLogHandler.swift +0 -79
- package/Sources/RunicCore/Logging/OSLogLogHandler.swift +0 -86
- package/Sources/RunicCore/Logging/RunicLog.swift +0 -123
- package/Sources/RunicCore/Models/EnhancedUsageModels.swift +0 -371
- package/Sources/RunicCore/OpenAIDashboardModels.swift +0 -210
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardBrowserCookieImporter.swift +0 -676
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardFetcher.swift +0 -492
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardNavigationDelegate.swift +0 -51
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardParser.swift +0 -483
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardScrapeScript.swift +0 -558
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardWebViewCache.swift +0 -204
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardWebsiteDataStore.swift +0 -78
- package/Sources/RunicCore/PathEnvironment.swift +0 -482
- package/Sources/RunicCore/Performance/PerformanceModels.swift +0 -371
- package/Sources/RunicCore/Performance/PerformanceStorageImpl.swift +0 -409
- package/Sources/RunicCore/Policy/UsagePolicyEngine.swift +0 -178
- package/Sources/RunicCore/ProjectBudgetStore.swift +0 -99
- package/Sources/RunicCore/ProviderCostSnapshot.swift +0 -29
- package/Sources/RunicCore/Providers/Antigravity/AntigravityProviderDescriptor.swift +0 -66
- package/Sources/RunicCore/Providers/Antigravity/AntigravityStatusProbe.swift +0 -685
- package/Sources/RunicCore/Providers/Auggie/AuggieProviderDescriptor.swift +0 -83
- package/Sources/RunicCore/Providers/Auggie/AuggieUsageFetcher.swift +0 -142
- package/Sources/RunicCore/Providers/Azure/AzureProviderDescriptor.swift +0 -141
- package/Sources/RunicCore/Providers/Azure/AzureUsageFetcher.swift +0 -188
- package/Sources/RunicCore/Providers/Bedrock/BedrockProviderDescriptor.swift +0 -126
- package/Sources/RunicCore/Providers/Bedrock/BedrockUsageFetcher.swift +0 -168
- package/Sources/RunicCore/Providers/Cerebras/CerebrasProviderDescriptor.swift +0 -84
- package/Sources/RunicCore/Providers/Cerebras/CerebrasUsageFetcher.swift +0 -75
- package/Sources/RunicCore/Providers/Claude/ClaudeCLISession.swift +0 -332
- package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthCredentials.swift +0 -180
- package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthUsageFetcher.swift +0 -137
- package/Sources/RunicCore/Providers/Claude/ClaudeProviderDescriptor.swift +0 -207
- package/Sources/RunicCore/Providers/Claude/ClaudeStatusProbe.swift +0 -654
- package/Sources/RunicCore/Providers/Claude/ClaudeUsageDataSource.swift +0 -28
- package/Sources/RunicCore/Providers/Claude/ClaudeUsageFetcher.swift +0 -480
- package/Sources/RunicCore/Providers/Claude/ClaudeWeb/ClaudeWebAPIFetcher.swift +0 -780
- package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthCredentials.swift +0 -147
- package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthUsageFetcher.swift +0 -280
- package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexTokenRefresher.swift +0 -100
- package/Sources/RunicCore/Providers/Codex/CodexProviderDescriptor.swift +0 -243
- package/Sources/RunicCore/Providers/Codex/CodexStatusProbe.swift +0 -125
- package/Sources/RunicCore/Providers/Codex/CodexUsageDataSource.swift +0 -24
- package/Sources/RunicCore/Providers/Codex/CodexWebDashboardStrategy.swift +0 -181
- package/Sources/RunicCore/Providers/Cohere/CohereProviderDescriptor.swift +0 -83
- package/Sources/RunicCore/Providers/Cohere/CohereUsageFetcher.swift +0 -85
- package/Sources/RunicCore/Providers/Copilot/CopilotDeviceFlow.swift +0 -123
- package/Sources/RunicCore/Providers/Copilot/CopilotGitHubCLITokenReader.swift +0 -114
- package/Sources/RunicCore/Providers/Copilot/CopilotProviderDescriptor.swift +0 -100
- package/Sources/RunicCore/Providers/Copilot/CopilotUsageFetcher.swift +0 -291
- package/Sources/RunicCore/Providers/Copilot/CopilotVSCodeTokenReader.swift +0 -386
- package/Sources/RunicCore/Providers/Cursor/CursorProviderDescriptor.swift +0 -65
- package/Sources/RunicCore/Providers/Cursor/CursorStatusProbe.swift +0 -595
- package/Sources/RunicCore/Providers/DeepSeek/DeepSeekProviderDescriptor.swift +0 -85
- package/Sources/RunicCore/Providers/DeepSeek/DeepSeekUsageFetcher.swift +0 -108
- package/Sources/RunicCore/Providers/Factory/FactoryLocalStorageImporter.swift +0 -398
- package/Sources/RunicCore/Providers/Factory/FactoryProviderDescriptor.swift +0 -65
- package/Sources/RunicCore/Providers/Factory/FactoryStatusProbe.swift +0 -1276
- package/Sources/RunicCore/Providers/Fireworks/FireworksProviderDescriptor.swift +0 -84
- package/Sources/RunicCore/Providers/Fireworks/FireworksUsageFetcher.swift +0 -75
- package/Sources/RunicCore/Providers/Gemini/GeminiProviderDescriptor.swift +0 -65
- package/Sources/RunicCore/Providers/Gemini/GeminiStatusProbe.swift +0 -836
- package/Sources/RunicCore/Providers/Groq/GroqProviderDescriptor.swift +0 -83
- package/Sources/RunicCore/Providers/Groq/GroqUsageFetcher.swift +0 -71
- package/Sources/RunicCore/Providers/Kimi/KimiProviderDescriptor.swift +0 -83
- package/Sources/RunicCore/Providers/Kimi/KimiUsageFetcher.swift +0 -77
- package/Sources/RunicCore/Providers/MiniMax/MiniMaxProviderDescriptor.swift +0 -92
- package/Sources/RunicCore/Providers/MiniMax/MiniMaxSettingsReader.swift +0 -54
- package/Sources/RunicCore/Providers/MiniMax/MiniMaxUsageFetcher.swift +0 -168
- package/Sources/RunicCore/Providers/MiniMax/MiniMaxWebUsageFetcher.swift +0 -911
- package/Sources/RunicCore/Providers/Mistral/MistralProviderDescriptor.swift +0 -84
- package/Sources/RunicCore/Providers/Mistral/MistralUsageFetcher.swift +0 -75
- package/Sources/RunicCore/Providers/OpenRouter/OpenRouterProviderDescriptor.swift +0 -87
- package/Sources/RunicCore/Providers/OpenRouter/OpenRouterUsageFetcher.swift +0 -203
- package/Sources/RunicCore/Providers/Perplexity/PerplexityProviderDescriptor.swift +0 -84
- package/Sources/RunicCore/Providers/Perplexity/PerplexityUsageFetcher.swift +0 -75
- package/Sources/RunicCore/Providers/ProviderBranding.swift +0 -25
- package/Sources/RunicCore/Providers/ProviderCLIConfig.swift +0 -17
- package/Sources/RunicCore/Providers/ProviderDescriptor.swift +0 -129
- package/Sources/RunicCore/Providers/ProviderFetchPlan.swift +0 -263
- package/Sources/RunicCore/Providers/ProviderSettingsSnapshot.swift +0 -98
- package/Sources/RunicCore/Providers/ProviderTokenResolver.swift +0 -501
- package/Sources/RunicCore/Providers/ProviderVersionDetector.swift +0 -68
- package/Sources/RunicCore/Providers/Providers.swift +0 -184
- package/Sources/RunicCore/Providers/Qwen/QwenProviderDescriptor.swift +0 -84
- package/Sources/RunicCore/Providers/Qwen/QwenSettingsReader.swift +0 -30
- package/Sources/RunicCore/Providers/Qwen/QwenUsageStats.swift +0 -315
- package/Sources/RunicCore/Providers/SambaNova/SambaNovaProviderDescriptor.swift +0 -84
- package/Sources/RunicCore/Providers/SambaNova/SambaNovaUsageFetcher.swift +0 -75
- package/Sources/RunicCore/Providers/Together/TogetherProviderDescriptor.swift +0 -83
- package/Sources/RunicCore/Providers/Together/TogetherUsageFetcher.swift +0 -75
- package/Sources/RunicCore/Providers/VertexAI/VertexAIProviderDescriptor.swift +0 -123
- package/Sources/RunicCore/Providers/VertexAI/VertexAISettingsReader.swift +0 -48
- package/Sources/RunicCore/Providers/VertexAI/VertexAIUsageFetcher.swift +0 -144
- package/Sources/RunicCore/Providers/XAI/XAIProviderDescriptor.swift +0 -83
- package/Sources/RunicCore/Providers/XAI/XAIUsageFetcher.swift +0 -75
- package/Sources/RunicCore/Providers/Zai/ZaiProviderDescriptor.swift +0 -72
- package/Sources/RunicCore/Providers/Zai/ZaiSettingsReader.swift +0 -41
- package/Sources/RunicCore/Providers/Zai/ZaiUsageStats.swift +0 -718
- package/Sources/RunicCore/Sync/BackgroundSyncManager.swift +0 -385
- package/Sources/RunicCore/Sync/SyncConflictResolver.swift +0 -310
- package/Sources/RunicCore/Sync/SyncProtocol.swift +0 -288
- package/Sources/RunicCore/Sync/SyncRecord.swift +0 -405
- package/Sources/RunicCore/Sync/SyncUsageExample.swift +0 -294
- package/Sources/RunicCore/Sync/TeamSyncRecords.swift +0 -775
- package/Sources/RunicCore/Sync/iCloudSyncEngine.swift +0 -333
- package/Sources/RunicCore/Team/TeamModels.swift +0 -583
- package/Sources/RunicCore/Team/TeamShowbackExporter.swift +0 -495
- package/Sources/RunicCore/Team/TeamStore.swift +0 -792
- package/Sources/RunicCore/TextParsing.swift +0 -55
- package/Sources/RunicCore/UsageFetcher.swift +0 -694
- package/Sources/RunicCore/UsageFormatter.swift +0 -410
- package/Sources/RunicCore/UsageLedger/ClaudeUsageLogSource.swift +0 -427
- package/Sources/RunicCore/UsageLedger/CodexUsageLogSource.swift +0 -494
- package/Sources/RunicCore/UsageLedger/LedgerCache.swift +0 -158
- package/Sources/RunicCore/UsageLedger/OTelGenAILedgerAdapter.swift +0 -550
- package/Sources/RunicCore/UsageLedger/UsageLedger.swift +0 -29
- package/Sources/RunicCore/UsageLedger/UsageLedgerAggregator.swift +0 -660
- package/Sources/RunicCore/UsageLedger/UsageLedgerInsightsAdvisor.swift +0 -209
- package/Sources/RunicCore/UsageLedger/UsageLedgerModels.swift +0 -417
- package/Sources/RunicCore/UsageLedger/UsageLedgerProjectIdentity.swift +0 -245
- package/Sources/RunicCore/UsagePace.swift +0 -81
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageCache.swift +0 -73
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageJsonl.swift +0 -74
- package/Sources/RunicCore/Vendored/CostUsage/CostUsagePricing.swift +0 -208
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner+Claude.swift +0 -455
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner+Timestamp.swift +0 -132
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner.swift +0 -589
- package/Sources/RunicCore/WidgetSnapshot.swift +0 -183
- package/Sources/RunicMacroSupport/ProviderRegistrationMacros.swift +0 -14
- package/Sources/RunicMacros/ProviderRegistrationMacros.swift +0 -216
- package/Sources/RunicWidget/RunicWidgetBundle.swift +0 -79
- package/Sources/RunicWidget/RunicWidgetProvider.swift +0 -283
- package/Sources/RunicWidget/RunicWidgetViews.swift +0 -680
- package/Tests/RunicTests/AntigravityStatusProbeTests.swift +0 -50
- package/Tests/RunicTests/AppDelegateTests.swift +0 -43
- package/Tests/RunicTests/BrowserCookieOrderLabelTests.swift +0 -22
- package/Tests/RunicTests/CLIArgumentParsingTests.swift +0 -70
- package/Tests/RunicTests/CLICostTests.swift +0 -65
- package/Tests/RunicTests/CLIProviderSelectionTests.swift +0 -22
- package/Tests/RunicTests/CLISnapshotTests.swift +0 -72
- package/Tests/RunicTests/CLIWebFallbackTests.swift +0 -58
- package/Tests/RunicTests/ClaudeOAuthTests.swift +0 -164
- package/Tests/RunicTests/ClaudeResilienceTests.swift +0 -30
- package/Tests/RunicTests/ClaudeUsageTests.swift +0 -370
- package/Tests/RunicTests/CodexOAuthTests.swift +0 -122
- package/Tests/RunicTests/CodexUsageLogSourceTests.swift +0 -82
- package/Tests/RunicTests/CopilotTokenResolverTests.swift +0 -75
- package/Tests/RunicTests/CopilotVSCodeTokenReaderTests.swift +0 -75
- package/Tests/RunicTests/CostUsageDecodingTests.swift +0 -394
- package/Tests/RunicTests/CostUsagePricingTests.swift +0 -50
- package/Tests/RunicTests/CostUsageScannerTests.swift +0 -700
- package/Tests/RunicTests/CursorStatusProbeTests.swift +0 -323
- package/Tests/RunicTests/FactoryStatusProbeTests.swift +0 -69
- package/Tests/RunicTests/GeminiAPITestHelpers.swift +0 -94
- package/Tests/RunicTests/GeminiLoginAlertTests.swift +0 -28
- package/Tests/RunicTests/GeminiStatusProbeAPITests.swift +0 -283
- package/Tests/RunicTests/GeminiStatusProbePlanTests.swift +0 -279
- package/Tests/RunicTests/GeminiStatusProbeTests.swift +0 -233
- package/Tests/RunicTests/GeminiTestEnvironment.swift +0 -87
- package/Tests/RunicTests/GoogleWorkspaceStatusTests.swift +0 -73
- package/Tests/RunicTests/InstallOriginTests.swift +0 -18
- package/Tests/RunicTests/KeyboardShortcutsBundleTests.swift +0 -9
- package/Tests/RunicTests/LiveAccountTests.swift +0 -24
- package/Tests/RunicTests/LoadingPatternTests.swift +0 -35
- package/Tests/RunicTests/MenuCardModelTests.swift +0 -545
- package/Tests/RunicTests/MiniMaxCookieHeaderStoreTestSupport.swift +0 -8
- package/Tests/RunicTests/MiniMaxGroupIDStoreTestSupport.swift +0 -8
- package/Tests/RunicTests/MiniMaxParsingTests.swift +0 -68
- package/Tests/RunicTests/MiniMaxTokenStoreTestSupport.swift +0 -8
- package/Tests/RunicTests/OTelGenAILedgerAdapterTests.swift +0 -112
- package/Tests/RunicTests/OpenAIDashboardBrowserCookieImporterTests.swift +0 -17
- package/Tests/RunicTests/OpenAIDashboardFetcherCreditsWaitTests.swift +0 -75
- package/Tests/RunicTests/OpenAIDashboardOffscreenHostTests.swift +0 -27
- package/Tests/RunicTests/OpenAIDashboardParserTests.swift +0 -134
- package/Tests/RunicTests/OpenAIWebAccountSwitchTests.swift +0 -53
- package/Tests/RunicTests/OpenRouterTokenStoreTestSupport.swift +0 -92
- package/Tests/RunicTests/PathBuilderTests.swift +0 -237
- package/Tests/RunicTests/ProviderFetchPipelineTests.swift +0 -160
- package/Tests/RunicTests/ProviderIconResourcesTests.swift +0 -38
- package/Tests/RunicTests/ProviderMetadataStatusLinkTests.swift +0 -16
- package/Tests/RunicTests/ProviderRegistryTests.swift +0 -29
- package/Tests/RunicTests/ProviderSettingsDescriptorTests.swift +0 -202
- package/Tests/RunicTests/ProviderToggleStoreTests.swift +0 -51
- package/Tests/RunicTests/RunicTests.swift +0 -120
- package/Tests/RunicTests/SessionQuotaNotificationLogicTests.swift +0 -36
- package/Tests/RunicTests/SettingsStoreTests.swift +0 -161
- package/Tests/RunicTests/StatusItemAnimationTests.swift +0 -49
- package/Tests/RunicTests/StatusMenuTests.swift +0 -434
- package/Tests/RunicTests/StatusProbeTests.swift +0 -377
- package/Tests/RunicTests/SubprocessRunnerTests.swift +0 -20
- package/Tests/RunicTests/SubscriptionDetectionTests.swift +0 -65
- package/Tests/RunicTests/TTYCommandRunnerTests.swift +0 -148
- package/Tests/RunicTests/TTYIntegrationTests.swift +0 -41
- package/Tests/RunicTests/TeamShowbackExporterTests.swift +0 -159
- package/Tests/RunicTests/TextParsingTests.swift +0 -12
- package/Tests/RunicTests/UsageFormatterTests.swift +0 -112
- package/Tests/RunicTests/UsageLedgerAnomalyDetectionTests.swift +0 -172
- package/Tests/RunicTests/UsageLedgerForecastTests.swift +0 -213
- package/Tests/RunicTests/UsageLedgerInsightsAdvisorTests.swift +0 -83
- package/Tests/RunicTests/UsageLedgerProjectNameTests.swift +0 -170
- package/Tests/RunicTests/UsagePaceTests.swift +0 -77
- package/Tests/RunicTests/UsagePaceTextTests.swift +0 -109
- package/Tests/RunicTests/UsagePolicyEngineTests.swift +0 -91
- package/Tests/RunicTests/WidgetSnapshotTests.swift +0 -45
- package/Tests/RunicTests/ZaiProviderTests.swift +0 -61
- package/Tests/RunicTests/ZaiTokenStoreTestSupport.swift +0 -6
- package/TestsLinux/PlatformGatingTests.swift +0 -46
- package/appcast.xml +0 -144
- package/assets/logo-concept-stack.svg +0 -24
- package/assets/logo-minimal-bars.svg +0 -15
- package/assets/logo.svg +0 -20
- package/assets/logo2.svg +0 -43
- package/bin/docs-list +0 -5
- package/build-and-run.sh +0 -369
- package/docs/.nojekyll +0 -1
- package/docs/CNAME +0 -1
- package/docs/antigravity.md +0 -75
- package/docs/architecture.md +0 -32
- package/docs/claude.md +0 -93
- package/docs/cli-commands/integration_guide.md +0 -371
- package/docs/cli-commands/quick_reference.md +0 -362
- package/docs/cli-commands/readme.md +0 -361
- package/docs/cli.md +0 -156
- package/docs/cloudkit_sync_guide.md +0 -495
- package/docs/codebase_review.md +0 -288
- package/docs/codex-oauth.md +0 -635
- package/docs/codex.md +0 -104
- package/docs/codexbar.png +0 -0
- package/docs/copilot.md +0 -44
- package/docs/cursor.md +0 -46
- package/docs/design/designcomparisonchart.md +0 -510
- package/docs/design/implementationguide.md +0 -792
- package/docs/design/menubaricondesignconcepts.md +0 -796
- package/docs/design/mockups/hybridiconconcept.svg +0 -62
- package/docs/design/mockups/infinityiconconcept.svg +0 -41
- package/docs/design/mockups/infinityiconstates.svg +0 -129
- package/docs/design/mockups/wavelogorefined.svg +0 -48
- package/docs/design/quick_summary.md +0 -426
- package/docs/design/readme.md +0 -478
- package/docs/design/sizespecifications.md +0 -575
- package/docs/design-system.md +0 -836
- package/docs/factory.md +0 -103
- package/docs/gemini.md +0 -73
- package/docs/icon.md +0 -37
- package/docs/icon.png +0 -0
- package/docs/index.html +0 -175
- package/docs/keychain_fix.md +0 -274
- package/docs/minimax.md +0 -71
- package/docs/packaging.md +0 -25
- package/docs/progress-bar-improvements.md +0 -240
- package/docs/progress-bar-quick-reference.md +0 -283
- package/docs/progress-bar-technical-details.md +0 -432
- package/docs/progress-bar-visual-test.swift +0 -375
- package/docs/provider.md +0 -202
- package/docs/providers.md +0 -86
- package/docs/refactor/macros.md +0 -35
- package/docs/refresh-loop.md +0 -22
- package/docs/releasing-homebrew.md +0 -35
- package/docs/releasing.md +0 -121
- package/docs/research/concrete_todo_2026-02-22.md +0 -47
- package/docs/research/core-feature-research.md +0 -248
- package/docs/research/feature_uiux_roadmap_2026-02-22.md +0 -202
- package/docs/research/parity_matrix.md +0 -49
- package/docs/research/provider_expansion_candidates_2026-02-22.md +0 -80
- package/docs/research/provider_model_token_project_matrix_2026-02-23.md +0 -46
- package/docs/research/release_gate_checklist.md +0 -57
- package/docs/site.css +0 -505
- package/docs/sparkle.md +0 -28
- package/docs/status.md +0 -28
- package/docs/sync/implementation.md +0 -393
- package/docs/sync/readme.md +0 -317
- package/docs/sync_files_summary.md +0 -391
- package/docs/sync_quick_reference.md +0 -225
- package/docs/todo.md +0 -11
- package/docs/ui.md +0 -29
- package/docs/web-integration.md +0 -9
- package/docs/widgets.md +0 -85
- package/docs/workflows/error-handling-improvements.md +0 -434
- package/docs/workflows/folder_structure.md +0 -299
- package/docs/workflows/loading_states.md +0 -446
- package/docs/workflows/loading_states_examples.md +0 -565
- package/docs/workflows/loading_states_flow.md +0 -430
- package/docs/workflows/performance_optimizations.md +0 -457
- package/docs/workflows/phase1-cli-testing-report.md +0 -313
- package/docs/workflows/quick_reference.md +0 -228
- package/docs/workflows/readme.md +0 -59
- package/docs/workflows/recent_improvements.md +0 -275
- package/docs/workflows/sync_enablement_summary.md +0 -400
- package/docs/zai.md +0 -43
- package/runic.png +0 -0
- package/version.env +0 -2
|
@@ -1,1711 +0,0 @@
|
|
|
1
|
-
import AppKit
|
|
2
|
-
import RunicCore
|
|
3
|
-
import Observation
|
|
4
|
-
import ServiceManagement
|
|
5
|
-
|
|
6
|
-
enum RefreshFrequency: String, CaseIterable, Identifiable {
|
|
7
|
-
case manual
|
|
8
|
-
case oneMinute
|
|
9
|
-
case twoMinutes
|
|
10
|
-
case fiveMinutes
|
|
11
|
-
case fifteenMinutes
|
|
12
|
-
|
|
13
|
-
var id: String { self.rawValue }
|
|
14
|
-
|
|
15
|
-
var seconds: TimeInterval? {
|
|
16
|
-
switch self {
|
|
17
|
-
case .manual: nil
|
|
18
|
-
case .oneMinute: 60
|
|
19
|
-
case .twoMinutes: 120
|
|
20
|
-
case .fiveMinutes: 300
|
|
21
|
-
case .fifteenMinutes: 900
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
var label: String {
|
|
26
|
-
switch self {
|
|
27
|
-
case .manual: "Manual"
|
|
28
|
-
case .oneMinute: "1 min"
|
|
29
|
-
case .twoMinutes: "2 min"
|
|
30
|
-
case .fiveMinutes: "5 min"
|
|
31
|
-
case .fifteenMinutes: "15 min"
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
enum UsageMetricDisplayMode: String, CaseIterable, Identifiable {
|
|
37
|
-
case barsAndPercent
|
|
38
|
-
case barsOnly
|
|
39
|
-
case percentOnly
|
|
40
|
-
|
|
41
|
-
var id: String { self.rawValue }
|
|
42
|
-
|
|
43
|
-
var label: String {
|
|
44
|
-
switch self {
|
|
45
|
-
case .barsAndPercent: "Bars + %"
|
|
46
|
-
case .barsOnly: "Bars"
|
|
47
|
-
case .percentOnly: "%"
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
var showsBars: Bool {
|
|
52
|
-
switch self {
|
|
53
|
-
case .barsAndPercent, .barsOnly:
|
|
54
|
-
true
|
|
55
|
-
case .percentOnly:
|
|
56
|
-
false
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
var showsPercent: Bool {
|
|
61
|
-
switch self {
|
|
62
|
-
case .barsAndPercent, .percentOnly:
|
|
63
|
-
true
|
|
64
|
-
case .barsOnly:
|
|
65
|
-
false
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
enum MenuMode: String, CaseIterable, Identifiable {
|
|
71
|
-
case glance
|
|
72
|
-
case analyst
|
|
73
|
-
case `operator`
|
|
74
|
-
|
|
75
|
-
var id: String { self.rawValue }
|
|
76
|
-
|
|
77
|
-
var label: String {
|
|
78
|
-
switch self {
|
|
79
|
-
case .glance:
|
|
80
|
-
"Glance"
|
|
81
|
-
case .analyst:
|
|
82
|
-
"Analyst"
|
|
83
|
-
case .`operator`:
|
|
84
|
-
"Operator"
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
enum ChartStyle: String, CaseIterable, Identifiable {
|
|
90
|
-
case line
|
|
91
|
-
case area
|
|
92
|
-
case bar
|
|
93
|
-
|
|
94
|
-
var id: String { self.rawValue }
|
|
95
|
-
|
|
96
|
-
var label: String {
|
|
97
|
-
switch self {
|
|
98
|
-
case .line: return "Line"
|
|
99
|
-
case .area: return "Area"
|
|
100
|
-
case .bar: return "Bar"
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
enum NumberFormat: String, CaseIterable, Identifiable {
|
|
106
|
-
case abbreviated
|
|
107
|
-
case full
|
|
108
|
-
|
|
109
|
-
var id: String { self.rawValue }
|
|
110
|
-
|
|
111
|
-
var label: String {
|
|
112
|
-
switch self {
|
|
113
|
-
case .abbreviated: return "Abbreviated"
|
|
114
|
-
case .full: return "Full"
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
enum DateFormat: String, CaseIterable, Identifiable {
|
|
120
|
-
case relative
|
|
121
|
-
case absolute
|
|
122
|
-
|
|
123
|
-
var id: String { self.rawValue }
|
|
124
|
-
|
|
125
|
-
var label: String {
|
|
126
|
-
switch self {
|
|
127
|
-
case .relative: return "Relative"
|
|
128
|
-
case .absolute: return "Absolute"
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
enum Theme: String, CaseIterable, Identifiable {
|
|
134
|
-
case system
|
|
135
|
-
case light
|
|
136
|
-
case dark
|
|
137
|
-
|
|
138
|
-
var id: String { self.rawValue }
|
|
139
|
-
|
|
140
|
-
var label: String {
|
|
141
|
-
switch self {
|
|
142
|
-
case .system: return "System"
|
|
143
|
-
case .light: return "Light"
|
|
144
|
-
case .dark: return "Dark"
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
enum ProviderSwitcherLayout: String, CaseIterable, Identifiable {
|
|
150
|
-
case top
|
|
151
|
-
case sidebar
|
|
152
|
-
|
|
153
|
-
var id: String { self.rawValue }
|
|
154
|
-
|
|
155
|
-
var label: String {
|
|
156
|
-
switch self {
|
|
157
|
-
case .top: return "Top"
|
|
158
|
-
case .sidebar: return "Sidebar"
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
enum ProviderSwitcherIconSize: String, CaseIterable, Identifiable {
|
|
164
|
-
case small
|
|
165
|
-
case medium
|
|
166
|
-
|
|
167
|
-
var id: String { self.rawValue }
|
|
168
|
-
|
|
169
|
-
var label: String {
|
|
170
|
-
switch self {
|
|
171
|
-
case .small: return "Small"
|
|
172
|
-
case .medium: return "Medium"
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
@MainActor
|
|
178
|
-
@Observable
|
|
179
|
-
final class SettingsStore {
|
|
180
|
-
/// Persisted provider display order.
|
|
181
|
-
///
|
|
182
|
-
/// Stored as raw `UsageProvider` strings so new providers can be appended automatically without breaking.
|
|
183
|
-
private var providerOrderRaw: [String] {
|
|
184
|
-
didSet { self.userDefaults.set(self.providerOrderRaw, forKey: "providerOrder") }
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
var refreshFrequency: RefreshFrequency {
|
|
188
|
-
didSet { self.userDefaults.set(self.refreshFrequency.rawValue, forKey: "refreshFrequency") }
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
var autoDisableRefreshWhenIdleEnabled: Bool {
|
|
192
|
-
didSet { self.userDefaults.set(self.autoDisableRefreshWhenIdleEnabled, forKey: "autoDisableRefreshWhenIdleEnabled") }
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
var autoDisableRefreshWhenIdleMinutes: Int {
|
|
196
|
-
didSet { self.userDefaults.set(self.autoDisableRefreshWhenIdleMinutes, forKey: "autoDisableRefreshWhenIdleMinutes") }
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
var autoDisableRefreshOnSleepEnabled: Bool {
|
|
200
|
-
didSet { self.userDefaults.set(self.autoDisableRefreshOnSleepEnabled, forKey: "autoDisableRefreshOnSleepEnabled") }
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
var autoRefreshWarningEnabled: Bool {
|
|
204
|
-
didSet { self.userDefaults.set(self.autoRefreshWarningEnabled, forKey: "autoRefreshWarningEnabled") }
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
var autoRefreshWarningThreshold: Int {
|
|
208
|
-
didSet { self.userDefaults.set(self.autoRefreshWarningThreshold, forKey: "autoRefreshWarningThreshold") }
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
var autoSuspendInactiveProvidersEnabled: Bool {
|
|
212
|
-
didSet {
|
|
213
|
-
self.userDefaults.set(self.autoSuspendInactiveProvidersEnabled, forKey: "autoSuspendInactiveProvidersEnabled")
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
var autoSuspendInactiveProvidersMinutes: Int {
|
|
218
|
-
didSet {
|
|
219
|
-
self.userDefaults.set(self.autoSuspendInactiveProvidersMinutes, forKey: "autoSuspendInactiveProvidersMinutes")
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
var launchAtLogin: Bool {
|
|
224
|
-
didSet {
|
|
225
|
-
self.userDefaults.set(self.launchAtLogin, forKey: "launchAtLogin")
|
|
226
|
-
LaunchAtLoginManager.setEnabled(self.launchAtLogin)
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
/// Hidden toggle to reveal debug-only menu items (enable via defaults write com.sriinnu.athena.Runic debugMenuEnabled
|
|
231
|
-
/// -bool YES).
|
|
232
|
-
var debugMenuEnabled: Bool {
|
|
233
|
-
didSet { self.userDefaults.set(self.debugMenuEnabled, forKey: "debugMenuEnabled") }
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
private var debugLoadingPatternRaw: String? {
|
|
237
|
-
didSet {
|
|
238
|
-
if let raw = self.debugLoadingPatternRaw {
|
|
239
|
-
self.userDefaults.set(raw, forKey: "debugLoadingPattern")
|
|
240
|
-
} else {
|
|
241
|
-
self.userDefaults.removeObject(forKey: "debugLoadingPattern")
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
var statusChecksEnabled: Bool {
|
|
247
|
-
didSet { self.userDefaults.set(self.statusChecksEnabled, forKey: "statusChecksEnabled") }
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
var sessionQuotaNotificationsEnabled: Bool {
|
|
251
|
-
didSet {
|
|
252
|
-
self.userDefaults.set(self.sessionQuotaNotificationsEnabled, forKey: "sessionQuotaNotificationsEnabled")
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/// When enabled, post macOS notifications when spend forecasts breach project budgets.
|
|
257
|
-
var budgetNotificationsEnabled: Bool {
|
|
258
|
-
didSet {
|
|
259
|
-
self.userDefaults.set(self.budgetNotificationsEnabled, forKey: "budgetNotificationsEnabled")
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/// When enabled, progress bars show "percent used" instead of "percent left".
|
|
264
|
-
var usageBarsShowUsed: Bool {
|
|
265
|
-
didSet { self.userDefaults.set(self.usageBarsShowUsed, forKey: "usageBarsShowUsed") }
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
var usageMetricDisplayMode: UsageMetricDisplayMode {
|
|
269
|
-
didSet {
|
|
270
|
-
self.userDefaults.set(self.usageMetricDisplayMode.rawValue, forKey: "usageMetricDisplayMode")
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
var menuMode: MenuMode {
|
|
275
|
-
didSet {
|
|
276
|
-
self.userDefaults.set(self.menuMode.rawValue, forKey: "menuMode")
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
var chartStyle: ChartStyle {
|
|
281
|
-
didSet { self.userDefaults.set(self.chartStyle.rawValue, forKey: "chartStyle") }
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
var numberFormat: NumberFormat {
|
|
285
|
-
didSet { self.userDefaults.set(self.numberFormat.rawValue, forKey: "numberFormat") }
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
var dateFormat: DateFormat {
|
|
289
|
-
didSet { self.userDefaults.set(self.dateFormat.rawValue, forKey: "dateFormat") }
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
var theme: Theme {
|
|
293
|
-
didSet {
|
|
294
|
-
self.userDefaults.set(self.theme.rawValue, forKey: "theme")
|
|
295
|
-
RunicApp.applyTheme(self.theme)
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/// Optional: use provider branding icons with a percentage in the menu bar.
|
|
300
|
-
var menuBarShowsBrandIconWithPercent: Bool {
|
|
301
|
-
didSet {
|
|
302
|
-
self.userDefaults.set(self.menuBarShowsBrandIconWithPercent, forKey: "menuBarShowsBrandIconWithPercent")
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/// Optional: render the menu bar icon with a vibrant, data-reactive color.
|
|
307
|
-
var menuBarVibrantIconEnabled: Bool {
|
|
308
|
-
didSet {
|
|
309
|
-
self.userDefaults.set(self.menuBarVibrantIconEnabled, forKey: "menuBarVibrantIconEnabled")
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
/// Optional: show provider cost summary from local usage logs (Codex + Claude).
|
|
314
|
-
var costUsageEnabled: Bool {
|
|
315
|
-
didSet { self.userDefaults.set(self.costUsageEnabled, forKey: "tokenCostUsageEnabled") }
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
/// Optional: limit how many insight rows appear in the menu before "More…".
|
|
319
|
-
var insightsMenuMaxItems: Int {
|
|
320
|
-
didSet { self.userDefaults.set(self.insightsMenuMaxItems, forKey: "insightsMenuMaxItems") }
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/// Optional: how many days to include in the insights report.
|
|
324
|
-
var insightsReportDays: Int {
|
|
325
|
-
didSet { self.userDefaults.set(self.insightsReportDays, forKey: "insightsReportDays") }
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
/// How many days of usage history to scan for ledger data (charts, breakdowns).
|
|
329
|
-
/// Options: 3, 7, 30, 365. Default: 30.
|
|
330
|
-
var ledgerMaxAgeDays: Int {
|
|
331
|
-
didSet { self.userDefaults.set(self.ledgerMaxAgeDays, forKey: "ledgerMaxAgeDays") }
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
var randomBlinkEnabled: Bool {
|
|
335
|
-
didSet { self.userDefaults.set(self.randomBlinkEnabled, forKey: "randomBlinkEnabled") }
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
/// Optional: augment Claude usage with claude.ai web API (via browser cookies),
|
|
339
|
-
/// incl. "Extra usage" spend.
|
|
340
|
-
var claudeWebExtrasEnabled: Bool {
|
|
341
|
-
didSet { self.userDefaults.set(self.claudeWebExtrasEnabled, forKey: "claudeWebExtrasEnabled") }
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
/// Optional: show Codex credits + Claude extra usage sections in the menu UI.
|
|
345
|
-
var showOptionalCreditsAndExtraUsage: Bool {
|
|
346
|
-
didSet {
|
|
347
|
-
self.userDefaults.set(self.showOptionalCreditsAndExtraUsage, forKey: "showOptionalCreditsAndExtraUsage")
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/// Optional: fetch OpenAI web dashboard extras for Codex (browser cookies).
|
|
352
|
-
var openAIWebAccessEnabled: Bool {
|
|
353
|
-
didSet { self.userDefaults.set(self.openAIWebAccessEnabled, forKey: "openAIWebAccessEnabled") }
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
private var codexUsageDataSourceRaw: String? {
|
|
357
|
-
didSet {
|
|
358
|
-
if let raw = self.codexUsageDataSourceRaw {
|
|
359
|
-
self.userDefaults.set(raw, forKey: "codexUsageDataSource")
|
|
360
|
-
} else {
|
|
361
|
-
self.userDefaults.removeObject(forKey: "codexUsageDataSource")
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
private var claudeUsageDataSourceRaw: String? {
|
|
367
|
-
didSet {
|
|
368
|
-
if let raw = self.claudeUsageDataSourceRaw {
|
|
369
|
-
self.userDefaults.set(raw, forKey: "claudeUsageDataSource")
|
|
370
|
-
} else {
|
|
371
|
-
self.userDefaults.removeObject(forKey: "claudeUsageDataSource")
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/// Optional: collapse provider icons into a single menu bar item with an in-menu switcher.
|
|
377
|
-
var mergeIcons: Bool {
|
|
378
|
-
didSet { self.userDefaults.set(self.mergeIcons, forKey: "mergeIcons") }
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/// Optional: show provider icons in the in-menu switcher.
|
|
382
|
-
var switcherShowsIcons: Bool {
|
|
383
|
-
didSet { self.userDefaults.set(self.switcherShowsIcons, forKey: "switcherShowsIcons") }
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/// Optional: position the provider switcher either on top or in a left sidebar.
|
|
387
|
-
var providerSwitcherLayout: ProviderSwitcherLayout {
|
|
388
|
-
didSet {
|
|
389
|
-
self.userDefaults.set(self.providerSwitcherLayout.rawValue, forKey: "providerSwitcherLayout")
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
/// Optional: size of provider icons in the switcher.
|
|
394
|
-
var providerSwitcherIconSize: ProviderSwitcherIconSize {
|
|
395
|
-
didSet {
|
|
396
|
-
self.userDefaults.set(self.providerSwitcherIconSize.rawValue, forKey: "providerSwitcherIconSize")
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
/// Show the built-in providers pane as a sidebar (true) or flat list (false).
|
|
401
|
-
var providersPaneSidebar: Bool {
|
|
402
|
-
didSet { self.userDefaults.set(self.providersPaneSidebar, forKey: "providersPaneSidebar") }
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
/// z.ai API token (stored in Keychain).
|
|
406
|
-
var zaiAPIToken: String {
|
|
407
|
-
didSet {
|
|
408
|
-
self.schedulePersistZaiAPIToken()
|
|
409
|
-
if !zaiAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
410
|
-
self.autoEnableProviderIfNeeded(cliName: "zai")
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
/// MiniMax API token (stored in Keychain).
|
|
416
|
-
var minimaxAPIToken: String {
|
|
417
|
-
didSet {
|
|
418
|
-
self.schedulePersistMiniMaxAPIToken()
|
|
419
|
-
if !minimaxAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
420
|
-
self.autoEnableProviderIfNeeded(cliName: "minimax")
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
/// MiniMax manual Cookie header (stored in Keychain).
|
|
426
|
-
var minimaxCookieHeader: String {
|
|
427
|
-
didSet {
|
|
428
|
-
self.schedulePersistMiniMaxCookieHeader()
|
|
429
|
-
if !minimaxCookieHeader.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
430
|
-
self.autoEnableProviderIfNeeded(cliName: "minimax")
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
/// MiniMax Group ID (stored in Keychain).
|
|
436
|
-
var minimaxGroupID: String {
|
|
437
|
-
didSet { self.schedulePersistMiniMaxGroupID() }
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
/// Copilot API token (stored in Keychain).
|
|
441
|
-
var copilotAPIToken: String {
|
|
442
|
-
didSet {
|
|
443
|
-
self.schedulePersistCopilotAPIToken()
|
|
444
|
-
if !copilotAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
445
|
-
self.autoEnableProviderIfNeeded(cliName: "copilot")
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
/// OpenRouter API key (stored in Keychain).
|
|
451
|
-
var openRouterAPIToken: String {
|
|
452
|
-
didSet {
|
|
453
|
-
self.schedulePersistOpenRouterAPIToken()
|
|
454
|
-
if !openRouterAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
455
|
-
self.autoEnableProviderIfNeeded(cliName: "openrouter")
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
/// Groq API key (stored in Keychain).
|
|
461
|
-
var groqAPIToken: String {
|
|
462
|
-
didSet {
|
|
463
|
-
self.schedulePersistGroqAPIToken()
|
|
464
|
-
if !groqAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
465
|
-
self.autoEnableProviderIfNeeded(cliName: "groq")
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
/// DeepSeek API key (stored in Keychain).
|
|
471
|
-
var deepSeekAPIToken: String {
|
|
472
|
-
didSet {
|
|
473
|
-
self.schedulePersistDeepSeekAPIToken()
|
|
474
|
-
if !deepSeekAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
475
|
-
self.autoEnableProviderIfNeeded(cliName: "deepseek")
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
/// Fireworks API key (stored in Keychain).
|
|
481
|
-
var fireworksAPIToken: String {
|
|
482
|
-
didSet {
|
|
483
|
-
self.schedulePersistFireworksAPIToken()
|
|
484
|
-
if !fireworksAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
485
|
-
self.autoEnableProviderIfNeeded(cliName: "fireworks")
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
/// Mistral API key (stored in Keychain).
|
|
491
|
-
var mistralAPIToken: String {
|
|
492
|
-
didSet {
|
|
493
|
-
self.schedulePersistMistralAPIToken()
|
|
494
|
-
if !mistralAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
495
|
-
self.autoEnableProviderIfNeeded(cliName: "mistral")
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
/// Perplexity API key (stored in Keychain).
|
|
501
|
-
var perplexityAPIToken: String {
|
|
502
|
-
didSet {
|
|
503
|
-
self.schedulePersistPerplexityAPIToken()
|
|
504
|
-
if !perplexityAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
505
|
-
self.autoEnableProviderIfNeeded(cliName: "perplexity")
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
/// Kimi API key (stored in Keychain).
|
|
511
|
-
var kimiAPIToken: String {
|
|
512
|
-
didSet {
|
|
513
|
-
self.schedulePersistKimiAPIToken()
|
|
514
|
-
if !kimiAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
515
|
-
self.autoEnableProviderIfNeeded(cliName: "kimi")
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
/// Auggie API token (stored in Keychain).
|
|
521
|
-
var auggieAPIToken: String {
|
|
522
|
-
didSet {
|
|
523
|
-
self.schedulePersistAuggieAPIToken()
|
|
524
|
-
if !auggieAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
525
|
-
self.autoEnableProviderIfNeeded(cliName: "auggie")
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
/// Together API key (stored in Keychain).
|
|
531
|
-
var togetherAPIToken: String {
|
|
532
|
-
didSet {
|
|
533
|
-
self.schedulePersistTogetherAPIToken()
|
|
534
|
-
if !togetherAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
535
|
-
self.autoEnableProviderIfNeeded(cliName: "together")
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
/// Cohere API key (stored in Keychain).
|
|
541
|
-
var cohereAPIToken: String {
|
|
542
|
-
didSet {
|
|
543
|
-
self.schedulePersistCohereAPIToken()
|
|
544
|
-
if !cohereAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
545
|
-
self.autoEnableProviderIfNeeded(cliName: "cohere")
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
/// xAI API key (stored in Keychain).
|
|
551
|
-
var xaiAPIToken: String {
|
|
552
|
-
didSet {
|
|
553
|
-
self.schedulePersistXAiAPIToken()
|
|
554
|
-
if !xaiAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
555
|
-
self.autoEnableProviderIfNeeded(cliName: "xai")
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
/// Cerebras API key (stored in Keychain).
|
|
561
|
-
var cerebrasAPIToken: String {
|
|
562
|
-
didSet {
|
|
563
|
-
self.schedulePersistCerebrasAPIToken()
|
|
564
|
-
if !cerebrasAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
565
|
-
self.autoEnableProviderIfNeeded(cliName: "cerebras")
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
/// Qwen DashScope API key (stored in Keychain).
|
|
571
|
-
var qwenAPIToken: String {
|
|
572
|
-
didSet {
|
|
573
|
-
self.schedulePersistQwenAPIToken()
|
|
574
|
-
if !qwenAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
575
|
-
self.autoEnableProviderIfNeeded(cliName: "qwen")
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
/// SambaNova API key (stored in Keychain).
|
|
581
|
-
var sambaNovaAPIToken: String {
|
|
582
|
-
didSet {
|
|
583
|
-
self.schedulePersistSambaNovaAPIToken()
|
|
584
|
-
if !sambaNovaAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
585
|
-
self.autoEnableProviderIfNeeded(cliName: "sambanova")
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
/// Azure OpenAI endpoint URL (stored in UserDefaults).
|
|
591
|
-
var azureOpenAIEndpoint: String {
|
|
592
|
-
didSet { self.userDefaults.set(self.azureOpenAIEndpoint, forKey: "azureOpenAIEndpoint") }
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
/// Azure OpenAI deployment name (stored in UserDefaults).
|
|
596
|
-
var azureOpenAIDeployment: String {
|
|
597
|
-
didSet { self.userDefaults.set(self.azureOpenAIDeployment, forKey: "azureOpenAIDeployment") }
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
/// Azure OpenAI API version (stored in UserDefaults).
|
|
601
|
-
var azureOpenAIAPIVersion: String {
|
|
602
|
-
didSet { self.userDefaults.set(self.azureOpenAIAPIVersion, forKey: "azureOpenAIAPIVersion") }
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
/// Azure OpenAI API key (stored in Keychain).
|
|
606
|
-
var azureOpenAIAPIToken: String {
|
|
607
|
-
didSet {
|
|
608
|
-
self.schedulePersistAzureOpenAIAPIToken()
|
|
609
|
-
if !azureOpenAIAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
610
|
-
self.autoEnableProviderIfNeeded(cliName: "azure")
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
/// Amazon Bedrock region (stored in UserDefaults).
|
|
616
|
-
var bedrockRegion: String {
|
|
617
|
-
didSet { self.userDefaults.set(self.bedrockRegion, forKey: "bedrockRegion") }
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
/// Optional AWS profile for Amazon Bedrock (stored in UserDefaults).
|
|
621
|
-
var bedrockAWSProfile: String {
|
|
622
|
-
didSet { self.userDefaults.set(self.bedrockAWSProfile, forKey: "bedrockAWSProfile") }
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
/// Optional model filter for Amazon Bedrock (stored in UserDefaults).
|
|
626
|
-
var bedrockModelID: String {
|
|
627
|
-
didSet { self.userDefaults.set(self.bedrockModelID, forKey: "bedrockModelID") }
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
/// Google Cloud project for Vertex AI (stored in UserDefaults).
|
|
631
|
-
var vertexaiProject: String {
|
|
632
|
-
didSet { self.userDefaults.set(self.vertexaiProject, forKey: "vertexaiProject") }
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
/// Google Cloud location/region for Vertex AI (stored in UserDefaults).
|
|
636
|
-
var vertexaiLocation: String {
|
|
637
|
-
didSet { self.userDefaults.set(self.vertexaiLocation, forKey: "vertexaiLocation") }
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
private var selectedMenuProviderRaw: String? {
|
|
641
|
-
didSet {
|
|
642
|
-
if let raw = self.selectedMenuProviderRaw {
|
|
643
|
-
self.userDefaults.set(raw, forKey: "selectedMenuProvider")
|
|
644
|
-
} else {
|
|
645
|
-
self.userDefaults.removeObject(forKey: "selectedMenuProvider")
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
/// Optional override for the loading animation pattern, exposed via the Debug tab.
|
|
651
|
-
var debugLoadingPattern: LoadingPattern? {
|
|
652
|
-
get { self.debugLoadingPatternRaw.flatMap(LoadingPattern.init(rawValue:)) }
|
|
653
|
-
set {
|
|
654
|
-
self.debugLoadingPatternRaw = newValue?.rawValue
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
var selectedMenuProvider: UsageProvider? {
|
|
659
|
-
get { self.selectedMenuProviderRaw.flatMap(UsageProvider.init(rawValue:)) }
|
|
660
|
-
set {
|
|
661
|
-
self.selectedMenuProviderRaw = newValue?.rawValue
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
var codexUsageDataSource: CodexUsageDataSource {
|
|
666
|
-
get { CodexUsageDataSource(rawValue: self.codexUsageDataSourceRaw ?? "") ?? .oauth }
|
|
667
|
-
set {
|
|
668
|
-
self.codexUsageDataSourceRaw = newValue.rawValue
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
var claudeUsageDataSource: ClaudeUsageDataSource {
|
|
673
|
-
get { ClaudeUsageDataSource(rawValue: self.claudeUsageDataSourceRaw ?? "") ?? .oauth }
|
|
674
|
-
set {
|
|
675
|
-
self.claudeUsageDataSourceRaw = newValue.rawValue
|
|
676
|
-
if newValue != .cli {
|
|
677
|
-
self.claudeWebExtrasEnabled = false
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
var menuObservationToken: Int {
|
|
683
|
-
_ = self.providerOrderRaw
|
|
684
|
-
_ = self.refreshFrequency
|
|
685
|
-
_ = self.autoDisableRefreshWhenIdleEnabled
|
|
686
|
-
_ = self.autoDisableRefreshWhenIdleMinutes
|
|
687
|
-
_ = self.autoDisableRefreshOnSleepEnabled
|
|
688
|
-
_ = self.autoRefreshWarningEnabled
|
|
689
|
-
_ = self.autoRefreshWarningThreshold
|
|
690
|
-
_ = self.autoSuspendInactiveProvidersEnabled
|
|
691
|
-
_ = self.autoSuspendInactiveProvidersMinutes
|
|
692
|
-
_ = self.launchAtLogin
|
|
693
|
-
_ = self.debugMenuEnabled
|
|
694
|
-
_ = self.statusChecksEnabled
|
|
695
|
-
_ = self.sessionQuotaNotificationsEnabled
|
|
696
|
-
_ = self.usageBarsShowUsed
|
|
697
|
-
_ = self.usageMetricDisplayMode
|
|
698
|
-
_ = self.menuMode
|
|
699
|
-
_ = self.chartStyle
|
|
700
|
-
_ = self.numberFormat
|
|
701
|
-
_ = self.dateFormat
|
|
702
|
-
_ = self.theme
|
|
703
|
-
_ = self.menuBarShowsBrandIconWithPercent
|
|
704
|
-
_ = self.menuBarVibrantIconEnabled
|
|
705
|
-
_ = self.costUsageEnabled
|
|
706
|
-
_ = self.insightsMenuMaxItems
|
|
707
|
-
_ = self.insightsReportDays
|
|
708
|
-
_ = self.ledgerMaxAgeDays
|
|
709
|
-
_ = self.randomBlinkEnabled
|
|
710
|
-
_ = self.claudeWebExtrasEnabled
|
|
711
|
-
_ = self.showOptionalCreditsAndExtraUsage
|
|
712
|
-
_ = self.openAIWebAccessEnabled
|
|
713
|
-
_ = self.codexUsageDataSource
|
|
714
|
-
_ = self.claudeUsageDataSource
|
|
715
|
-
_ = self.mergeIcons
|
|
716
|
-
_ = self.switcherShowsIcons
|
|
717
|
-
_ = self.providerSwitcherLayout
|
|
718
|
-
_ = self.providerSwitcherIconSize
|
|
719
|
-
_ = self.zaiAPIToken
|
|
720
|
-
_ = self.minimaxAPIToken
|
|
721
|
-
_ = self.minimaxCookieHeader
|
|
722
|
-
_ = self.minimaxGroupID
|
|
723
|
-
_ = self.copilotAPIToken
|
|
724
|
-
_ = self.openRouterAPIToken
|
|
725
|
-
_ = self.groqAPIToken
|
|
726
|
-
_ = self.deepSeekAPIToken
|
|
727
|
-
_ = self.fireworksAPIToken
|
|
728
|
-
_ = self.mistralAPIToken
|
|
729
|
-
_ = self.perplexityAPIToken
|
|
730
|
-
_ = self.kimiAPIToken
|
|
731
|
-
_ = self.auggieAPIToken
|
|
732
|
-
_ = self.togetherAPIToken
|
|
733
|
-
_ = self.cohereAPIToken
|
|
734
|
-
_ = self.xaiAPIToken
|
|
735
|
-
_ = self.cerebrasAPIToken
|
|
736
|
-
_ = self.qwenAPIToken
|
|
737
|
-
_ = self.sambaNovaAPIToken
|
|
738
|
-
_ = self.azureOpenAIEndpoint
|
|
739
|
-
_ = self.azureOpenAIDeployment
|
|
740
|
-
_ = self.azureOpenAIAPIVersion
|
|
741
|
-
_ = self.azureOpenAIAPIToken
|
|
742
|
-
_ = self.bedrockRegion
|
|
743
|
-
_ = self.bedrockAWSProfile
|
|
744
|
-
_ = self.bedrockModelID
|
|
745
|
-
_ = self.vertexaiProject
|
|
746
|
-
_ = self.vertexaiLocation
|
|
747
|
-
_ = self.debugLoadingPattern
|
|
748
|
-
_ = self.selectedMenuProvider
|
|
749
|
-
_ = self.providerToggleRevision
|
|
750
|
-
return 0
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
private var providerDetectionCompleted: Bool {
|
|
754
|
-
didSet { self.userDefaults.set(self.providerDetectionCompleted, forKey: "providerDetectionCompleted") }
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
@ObservationIgnored private let userDefaults: UserDefaults
|
|
758
|
-
@ObservationIgnored private let toggleStore: ProviderToggleStore
|
|
759
|
-
@ObservationIgnored private let zaiTokenStore: any ZaiTokenStoring
|
|
760
|
-
@ObservationIgnored private var zaiTokenPersistTask: Task<Void, Never>?
|
|
761
|
-
@ObservationIgnored private let minimaxTokenStore: any MiniMaxTokenStoring
|
|
762
|
-
@ObservationIgnored private var minimaxTokenPersistTask: Task<Void, Never>?
|
|
763
|
-
@ObservationIgnored private let minimaxCookieHeaderStore: any MiniMaxCookieHeaderStoring
|
|
764
|
-
@ObservationIgnored private var minimaxCookieHeaderPersistTask: Task<Void, Never>?
|
|
765
|
-
@ObservationIgnored private let minimaxGroupIDStore: any MiniMaxGroupIDStoring
|
|
766
|
-
@ObservationIgnored private var minimaxGroupIDPersistTask: Task<Void, Never>?
|
|
767
|
-
@ObservationIgnored private let copilotTokenStore: any CopilotTokenStoring
|
|
768
|
-
@ObservationIgnored private var copilotTokenPersistTask: Task<Void, Never>?
|
|
769
|
-
@ObservationIgnored private let openRouterTokenStore: any OpenRouterTokenStoring
|
|
770
|
-
@ObservationIgnored private var openRouterTokenPersistTask: Task<Void, Never>?
|
|
771
|
-
@ObservationIgnored private let groqTokenStore: any GroqTokenStoring
|
|
772
|
-
@ObservationIgnored private var groqTokenPersistTask: Task<Void, Never>?
|
|
773
|
-
@ObservationIgnored private let deepSeekTokenStore: any DeepSeekTokenStoring
|
|
774
|
-
@ObservationIgnored private var deepSeekTokenPersistTask: Task<Void, Never>?
|
|
775
|
-
@ObservationIgnored private let fireworksTokenStore: any FireworksTokenStoring
|
|
776
|
-
@ObservationIgnored private var fireworksTokenPersistTask: Task<Void, Never>?
|
|
777
|
-
@ObservationIgnored private let mistralTokenStore: any MistralTokenStoring
|
|
778
|
-
@ObservationIgnored private var mistralTokenPersistTask: Task<Void, Never>?
|
|
779
|
-
@ObservationIgnored private let perplexityTokenStore: any PerplexityTokenStoring
|
|
780
|
-
@ObservationIgnored private var perplexityTokenPersistTask: Task<Void, Never>?
|
|
781
|
-
@ObservationIgnored private let kimiTokenStore: any KimiTokenStoring
|
|
782
|
-
@ObservationIgnored private var kimiTokenPersistTask: Task<Void, Never>?
|
|
783
|
-
@ObservationIgnored private let auggieTokenStore: any AuggieTokenStoring
|
|
784
|
-
@ObservationIgnored private var auggieTokenPersistTask: Task<Void, Never>?
|
|
785
|
-
@ObservationIgnored private let togetherTokenStore: any TogetherTokenStoring
|
|
786
|
-
@ObservationIgnored private var togetherTokenPersistTask: Task<Void, Never>?
|
|
787
|
-
@ObservationIgnored private let cohereTokenStore: any CohereTokenStoring
|
|
788
|
-
@ObservationIgnored private var cohereTokenPersistTask: Task<Void, Never>?
|
|
789
|
-
@ObservationIgnored private let xaiTokenStore: any XAITokenStoring
|
|
790
|
-
@ObservationIgnored private var xaiTokenPersistTask: Task<Void, Never>?
|
|
791
|
-
@ObservationIgnored private let cerebrasTokenStore: any CerebrasTokenStoring
|
|
792
|
-
@ObservationIgnored private var cerebrasTokenPersistTask: Task<Void, Never>?
|
|
793
|
-
@ObservationIgnored private let sambaNovaTokenStore: any SambaNovaTokenStoring
|
|
794
|
-
@ObservationIgnored private var sambaNovaTokenPersistTask: Task<Void, Never>?
|
|
795
|
-
@ObservationIgnored private let qwenTokenStore: any QwenTokenStoring
|
|
796
|
-
@ObservationIgnored private var qwenTokenPersistTask: Task<Void, Never>?
|
|
797
|
-
@ObservationIgnored private let azureOpenAITokenStore: any AzureOpenAITokenStoring
|
|
798
|
-
@ObservationIgnored private var azureOpenAITokenPersistTask: Task<Void, Never>?
|
|
799
|
-
// Cache enablement so tight UI loops (menu bar animations) don't hit UserDefaults each tick.
|
|
800
|
-
@ObservationIgnored private var cachedProviderEnablement: [UsageProvider: Bool] = [:]
|
|
801
|
-
@ObservationIgnored private var cachedProviderEnablementRevision: Int = -1
|
|
802
|
-
@ObservationIgnored private var cachedEnabledProviders: [UsageProvider] = []
|
|
803
|
-
@ObservationIgnored private var cachedEnabledProvidersRevision: Int = -1
|
|
804
|
-
@ObservationIgnored private var cachedEnabledProvidersOrderRaw: [String] = []
|
|
805
|
-
// Cache order to avoid re-building sets/arrays every animation tick.
|
|
806
|
-
@ObservationIgnored private var cachedProviderOrder: [UsageProvider] = []
|
|
807
|
-
@ObservationIgnored private var cachedProviderOrderRaw: [String] = []
|
|
808
|
-
private var providerToggleRevision: Int = 0
|
|
809
|
-
|
|
810
|
-
init(
|
|
811
|
-
userDefaults: UserDefaults = .standard,
|
|
812
|
-
zaiTokenStore: any ZaiTokenStoring = KeychainZaiTokenStore(),
|
|
813
|
-
minimaxTokenStore: any MiniMaxTokenStoring = KeychainMiniMaxTokenStore(),
|
|
814
|
-
minimaxCookieHeaderStore: any MiniMaxCookieHeaderStoring = KeychainMiniMaxCookieHeaderStore(),
|
|
815
|
-
minimaxGroupIDStore: any MiniMaxGroupIDStoring = KeychainMiniMaxGroupIDStore(),
|
|
816
|
-
copilotTokenStore: any CopilotTokenStoring = KeychainCopilotTokenStore(),
|
|
817
|
-
openRouterTokenStore: any OpenRouterTokenStoring = KeychainOpenRouterTokenStore(),
|
|
818
|
-
groqTokenStore: any GroqTokenStoring = KeychainGroqTokenStore(),
|
|
819
|
-
deepSeekTokenStore: any DeepSeekTokenStoring = KeychainDeepSeekTokenStore(),
|
|
820
|
-
fireworksTokenStore: any FireworksTokenStoring = KeychainFireworksTokenStore(),
|
|
821
|
-
mistralTokenStore: any MistralTokenStoring = KeychainMistralTokenStore(),
|
|
822
|
-
perplexityTokenStore: any PerplexityTokenStoring = KeychainPerplexityTokenStore(),
|
|
823
|
-
kimiTokenStore: any KimiTokenStoring = KeychainKimiTokenStore(),
|
|
824
|
-
auggieTokenStore: any AuggieTokenStoring = KeychainAuggieTokenStore(),
|
|
825
|
-
togetherTokenStore: any TogetherTokenStoring = KeychainTogetherTokenStore(),
|
|
826
|
-
cohereTokenStore: any CohereTokenStoring = KeychainCohereTokenStore(),
|
|
827
|
-
xaiTokenStore: any XAITokenStoring = KeychainXAITokenStore(),
|
|
828
|
-
cerebrasTokenStore: any CerebrasTokenStoring = KeychainCerebrasTokenStore(),
|
|
829
|
-
sambaNovaTokenStore: any SambaNovaTokenStoring = KeychainSambaNovaTokenStore(),
|
|
830
|
-
qwenTokenStore: any QwenTokenStoring = KeychainQwenTokenStore(),
|
|
831
|
-
azureOpenAITokenStore: any AzureOpenAITokenStoring = KeychainAzureOpenAITokenStore())
|
|
832
|
-
{
|
|
833
|
-
self.userDefaults = userDefaults
|
|
834
|
-
self.zaiTokenStore = zaiTokenStore
|
|
835
|
-
self.minimaxTokenStore = minimaxTokenStore
|
|
836
|
-
self.minimaxCookieHeaderStore = minimaxCookieHeaderStore
|
|
837
|
-
self.minimaxGroupIDStore = minimaxGroupIDStore
|
|
838
|
-
self.copilotTokenStore = copilotTokenStore
|
|
839
|
-
self.openRouterTokenStore = openRouterTokenStore
|
|
840
|
-
self.groqTokenStore = groqTokenStore
|
|
841
|
-
self.deepSeekTokenStore = deepSeekTokenStore
|
|
842
|
-
self.fireworksTokenStore = fireworksTokenStore
|
|
843
|
-
self.mistralTokenStore = mistralTokenStore
|
|
844
|
-
self.perplexityTokenStore = perplexityTokenStore
|
|
845
|
-
self.kimiTokenStore = kimiTokenStore
|
|
846
|
-
self.auggieTokenStore = auggieTokenStore
|
|
847
|
-
self.togetherTokenStore = togetherTokenStore
|
|
848
|
-
self.cohereTokenStore = cohereTokenStore
|
|
849
|
-
self.xaiTokenStore = xaiTokenStore
|
|
850
|
-
self.cerebrasTokenStore = cerebrasTokenStore
|
|
851
|
-
self.sambaNovaTokenStore = sambaNovaTokenStore
|
|
852
|
-
self.qwenTokenStore = qwenTokenStore
|
|
853
|
-
self.azureOpenAITokenStore = azureOpenAITokenStore
|
|
854
|
-
self.providerOrderRaw = userDefaults.stringArray(forKey: "providerOrder") ?? []
|
|
855
|
-
let raw = userDefaults.string(forKey: "refreshFrequency") ?? RefreshFrequency.manual.rawValue
|
|
856
|
-
self.refreshFrequency = RefreshFrequency(rawValue: raw) ?? .manual
|
|
857
|
-
self.autoDisableRefreshWhenIdleEnabled = userDefaults.object(
|
|
858
|
-
forKey: "autoDisableRefreshWhenIdleEnabled") as? Bool ?? true
|
|
859
|
-
self.autoDisableRefreshWhenIdleMinutes = userDefaults.object(
|
|
860
|
-
forKey: "autoDisableRefreshWhenIdleMinutes") as? Int ?? 5
|
|
861
|
-
self.autoDisableRefreshOnSleepEnabled = userDefaults.object(
|
|
862
|
-
forKey: "autoDisableRefreshOnSleepEnabled") as? Bool ?? true
|
|
863
|
-
self.autoRefreshWarningEnabled = userDefaults.object(
|
|
864
|
-
forKey: "autoRefreshWarningEnabled") as? Bool ?? true
|
|
865
|
-
self.autoRefreshWarningThreshold = userDefaults.object(
|
|
866
|
-
forKey: "autoRefreshWarningThreshold") as? Int ?? 10
|
|
867
|
-
self.autoSuspendInactiveProvidersEnabled = userDefaults.object(
|
|
868
|
-
forKey: "autoSuspendInactiveProvidersEnabled") as? Bool ?? true
|
|
869
|
-
self.autoSuspendInactiveProvidersMinutes = userDefaults.object(
|
|
870
|
-
forKey: "autoSuspendInactiveProvidersMinutes") as? Int ?? 720
|
|
871
|
-
self.launchAtLogin = userDefaults.object(forKey: "launchAtLogin") as? Bool ?? false
|
|
872
|
-
self.debugMenuEnabled = userDefaults.object(forKey: "debugMenuEnabled") as? Bool ?? false
|
|
873
|
-
self.debugLoadingPatternRaw = userDefaults.string(forKey: "debugLoadingPattern")
|
|
874
|
-
self.statusChecksEnabled = userDefaults.object(forKey: "statusChecksEnabled") as? Bool ?? true
|
|
875
|
-
let sessionQuotaNotificationsDefault = userDefaults.object(
|
|
876
|
-
forKey: "sessionQuotaNotificationsEnabled") as? Bool
|
|
877
|
-
self.sessionQuotaNotificationsEnabled = sessionQuotaNotificationsDefault ?? true
|
|
878
|
-
if sessionQuotaNotificationsDefault == nil {
|
|
879
|
-
self.userDefaults.set(true, forKey: "sessionQuotaNotificationsEnabled")
|
|
880
|
-
}
|
|
881
|
-
self.budgetNotificationsEnabled = userDefaults.object(
|
|
882
|
-
forKey: "budgetNotificationsEnabled") as? Bool ?? false
|
|
883
|
-
self.usageBarsShowUsed = userDefaults.object(forKey: "usageBarsShowUsed") as? Bool ?? true
|
|
884
|
-
let metricDisplayRaw = userDefaults.string(forKey: "usageMetricDisplayMode")
|
|
885
|
-
self.usageMetricDisplayMode = UsageMetricDisplayMode(rawValue: metricDisplayRaw ?? "") ?? .barsAndPercent
|
|
886
|
-
let menuModeRaw = userDefaults.string(forKey: "menuMode")
|
|
887
|
-
self.menuMode = MenuMode(rawValue: menuModeRaw ?? "") ?? .`operator`
|
|
888
|
-
let chartStyleRaw = userDefaults.string(forKey: "chartStyle")
|
|
889
|
-
self.chartStyle = ChartStyle(rawValue: chartStyleRaw ?? "") ?? .line
|
|
890
|
-
let numberFormatRaw = userDefaults.string(forKey: "numberFormat")
|
|
891
|
-
self.numberFormat = NumberFormat(rawValue: numberFormatRaw ?? "") ?? .abbreviated
|
|
892
|
-
let dateFormatRaw = userDefaults.string(forKey: "dateFormat")
|
|
893
|
-
self.dateFormat = DateFormat(rawValue: dateFormatRaw ?? "") ?? .relative
|
|
894
|
-
let themeRaw = userDefaults.string(forKey: "theme")
|
|
895
|
-
self.theme = Theme(rawValue: themeRaw ?? "") ?? .system
|
|
896
|
-
self.menuBarShowsBrandIconWithPercent = userDefaults.object(
|
|
897
|
-
forKey: "menuBarShowsBrandIconWithPercent") as? Bool ?? false
|
|
898
|
-
self.menuBarVibrantIconEnabled = userDefaults.object(
|
|
899
|
-
forKey: "menuBarVibrantIconEnabled") as? Bool ?? true
|
|
900
|
-
self.costUsageEnabled = userDefaults.object(forKey: "tokenCostUsageEnabled") as? Bool ?? true
|
|
901
|
-
self.insightsMenuMaxItems = userDefaults.object(forKey: "insightsMenuMaxItems") as? Int ?? 4
|
|
902
|
-
self.insightsReportDays = userDefaults.object(forKey: "insightsReportDays") as? Int ?? 7
|
|
903
|
-
self.ledgerMaxAgeDays = userDefaults.object(forKey: "ledgerMaxAgeDays") as? Int ?? 30
|
|
904
|
-
self.randomBlinkEnabled = userDefaults.object(forKey: "randomBlinkEnabled") as? Bool ?? false
|
|
905
|
-
self.claudeWebExtrasEnabled = userDefaults.object(forKey: "claudeWebExtrasEnabled") as? Bool ?? false
|
|
906
|
-
let creditsExtrasDefault = userDefaults.object(forKey: "showOptionalCreditsAndExtraUsage") as? Bool
|
|
907
|
-
self.showOptionalCreditsAndExtraUsage = creditsExtrasDefault ?? true
|
|
908
|
-
if creditsExtrasDefault == nil {
|
|
909
|
-
self.userDefaults.set(true, forKey: "showOptionalCreditsAndExtraUsage")
|
|
910
|
-
}
|
|
911
|
-
let openAIWebAccessDefault = userDefaults.object(forKey: "openAIWebAccessEnabled") as? Bool
|
|
912
|
-
self.openAIWebAccessEnabled = openAIWebAccessDefault ?? true
|
|
913
|
-
if openAIWebAccessDefault == nil {
|
|
914
|
-
self.userDefaults.set(true, forKey: "openAIWebAccessEnabled")
|
|
915
|
-
}
|
|
916
|
-
let codexSourceRaw = userDefaults.string(forKey: "codexUsageDataSource")
|
|
917
|
-
self.codexUsageDataSourceRaw = codexSourceRaw ?? CodexUsageDataSource.oauth.rawValue
|
|
918
|
-
let claudeSourceRaw = userDefaults.string(forKey: "claudeUsageDataSource")
|
|
919
|
-
self.claudeUsageDataSourceRaw = claudeSourceRaw ?? ClaudeUsageDataSource.oauth.rawValue
|
|
920
|
-
self.mergeIcons = userDefaults.object(forKey: "mergeIcons") as? Bool ?? true
|
|
921
|
-
self.switcherShowsIcons = userDefaults.object(forKey: "switcherShowsIcons") as? Bool ?? true
|
|
922
|
-
let layoutRaw = userDefaults.string(forKey: "providerSwitcherLayout")
|
|
923
|
-
self.providerSwitcherLayout = ProviderSwitcherLayout(rawValue: layoutRaw ?? "") ?? .top
|
|
924
|
-
let iconSizeRaw = userDefaults.string(forKey: "providerSwitcherIconSize")
|
|
925
|
-
self.providerSwitcherIconSize = ProviderSwitcherIconSize(rawValue: iconSizeRaw ?? "") ?? .medium
|
|
926
|
-
self.providersPaneSidebar = userDefaults.object(forKey: "providersPaneSidebar") as? Bool ?? false
|
|
927
|
-
self.azureOpenAIEndpoint = userDefaults.string(forKey: "azureOpenAIEndpoint") ?? ""
|
|
928
|
-
self.azureOpenAIDeployment = userDefaults.string(forKey: "azureOpenAIDeployment") ?? ""
|
|
929
|
-
self.azureOpenAIAPIVersion = userDefaults.string(forKey: "azureOpenAIAPIVersion")
|
|
930
|
-
?? "2024-10-21"
|
|
931
|
-
self.bedrockRegion = userDefaults.string(forKey: "bedrockRegion") ?? ""
|
|
932
|
-
self.bedrockAWSProfile = userDefaults.string(forKey: "bedrockAWSProfile") ?? ""
|
|
933
|
-
self.bedrockModelID = userDefaults.string(forKey: "bedrockModelID") ?? ""
|
|
934
|
-
self.vertexaiProject = userDefaults.string(forKey: "vertexaiProject") ?? ""
|
|
935
|
-
self.vertexaiLocation = userDefaults.string(forKey: "vertexaiLocation") ?? ""
|
|
936
|
-
self.zaiAPIToken = (try? zaiTokenStore.loadToken()) ?? ""
|
|
937
|
-
self.minimaxAPIToken = (try? minimaxTokenStore.loadToken()) ?? ""
|
|
938
|
-
self.minimaxCookieHeader = (try? minimaxCookieHeaderStore.loadHeader()) ?? ""
|
|
939
|
-
self.minimaxGroupID = (try? minimaxGroupIDStore.loadGroupID()) ?? ""
|
|
940
|
-
self.copilotAPIToken = (try? copilotTokenStore.loadToken()) ?? ""
|
|
941
|
-
self.openRouterAPIToken = (try? openRouterTokenStore.loadToken()) ?? ""
|
|
942
|
-
self.groqAPIToken = (try? groqTokenStore.loadToken()) ?? ""
|
|
943
|
-
self.deepSeekAPIToken = (try? deepSeekTokenStore.loadToken()) ?? ""
|
|
944
|
-
self.fireworksAPIToken = (try? fireworksTokenStore.loadToken()) ?? ""
|
|
945
|
-
self.mistralAPIToken = (try? mistralTokenStore.loadToken()) ?? ""
|
|
946
|
-
self.perplexityAPIToken = (try? perplexityTokenStore.loadToken()) ?? ""
|
|
947
|
-
self.kimiAPIToken = (try? kimiTokenStore.loadToken()) ?? ""
|
|
948
|
-
self.auggieAPIToken = (try? auggieTokenStore.loadToken()) ?? ""
|
|
949
|
-
self.togetherAPIToken = (try? togetherTokenStore.loadToken()) ?? ""
|
|
950
|
-
self.cohereAPIToken = (try? cohereTokenStore.loadToken()) ?? ""
|
|
951
|
-
self.xaiAPIToken = (try? xaiTokenStore.loadToken()) ?? ""
|
|
952
|
-
self.cerebrasAPIToken = (try? cerebrasTokenStore.loadToken()) ?? ""
|
|
953
|
-
self.sambaNovaAPIToken = (try? sambaNovaTokenStore.loadToken()) ?? ""
|
|
954
|
-
self.qwenAPIToken = (try? qwenTokenStore.loadToken()) ?? ""
|
|
955
|
-
self.azureOpenAIAPIToken = (try? azureOpenAITokenStore.loadToken()) ?? ""
|
|
956
|
-
// Always start on Overview tab.
|
|
957
|
-
self.selectedMenuProviderRaw = nil
|
|
958
|
-
self.providerDetectionCompleted = userDefaults.object(
|
|
959
|
-
forKey: "providerDetectionCompleted") as? Bool ?? false
|
|
960
|
-
self.toggleStore = ProviderToggleStore(userDefaults: userDefaults)
|
|
961
|
-
self.toggleStore.purgeLegacyKeys()
|
|
962
|
-
LaunchAtLoginManager.setEnabled(self.launchAtLogin)
|
|
963
|
-
self.runInitialProviderDetectionIfNeeded()
|
|
964
|
-
self.applyTokenCostDefaultIfNeeded()
|
|
965
|
-
if self.claudeUsageDataSource != .cli {
|
|
966
|
-
self.claudeWebExtrasEnabled = false
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
func orderedProviders() -> [UsageProvider] {
|
|
971
|
-
let raw = self.providerOrderRaw
|
|
972
|
-
if raw == self.cachedProviderOrderRaw, !self.cachedProviderOrder.isEmpty {
|
|
973
|
-
return self.cachedProviderOrder
|
|
974
|
-
}
|
|
975
|
-
let ordered = Self.effectiveProviderOrder(raw: raw)
|
|
976
|
-
self.cachedProviderOrderRaw = raw
|
|
977
|
-
self.cachedProviderOrder = ordered
|
|
978
|
-
return ordered
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
func moveProvider(fromOffsets: IndexSet, toOffset: Int) {
|
|
982
|
-
var order = self.orderedProviders()
|
|
983
|
-
order.move(fromOffsets: fromOffsets, toOffset: toOffset)
|
|
984
|
-
self.providerOrderRaw = order.map(\.rawValue)
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
func isProviderEnabled(provider: UsageProvider, metadata: ProviderMetadata) -> Bool {
|
|
988
|
-
_ = self.providerToggleRevision
|
|
989
|
-
return self.toggleStore.isEnabled(metadata: metadata)
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
func isProviderEnabledCached(
|
|
993
|
-
provider: UsageProvider,
|
|
994
|
-
metadataByProvider: [UsageProvider: ProviderMetadata]) -> Bool
|
|
995
|
-
{
|
|
996
|
-
self.refreshProviderEnablementCacheIfNeeded(metadataByProvider: metadataByProvider)
|
|
997
|
-
return self.cachedProviderEnablement[provider] ?? false
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
func enabledProvidersOrdered(metadataByProvider: [UsageProvider: ProviderMetadata]) -> [UsageProvider] {
|
|
1001
|
-
self.refreshProviderEnablementCacheIfNeeded(metadataByProvider: metadataByProvider)
|
|
1002
|
-
let orderRaw = self.providerOrderRaw
|
|
1003
|
-
let revision = self.cachedProviderEnablementRevision
|
|
1004
|
-
if revision == self.cachedEnabledProvidersRevision,
|
|
1005
|
-
orderRaw == self.cachedEnabledProvidersOrderRaw,
|
|
1006
|
-
!self.cachedEnabledProviders.isEmpty
|
|
1007
|
-
{
|
|
1008
|
-
return self.cachedEnabledProviders
|
|
1009
|
-
}
|
|
1010
|
-
let enabled = self.orderedProviders().filter { self.cachedProviderEnablement[$0] ?? false }
|
|
1011
|
-
self.cachedEnabledProviders = enabled
|
|
1012
|
-
self.cachedEnabledProvidersRevision = revision
|
|
1013
|
-
self.cachedEnabledProvidersOrderRaw = orderRaw
|
|
1014
|
-
return enabled
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1017
|
-
func setProviderEnabled(provider: UsageProvider, metadata: ProviderMetadata, enabled: Bool) {
|
|
1018
|
-
self.providerToggleRevision &+= 1
|
|
1019
|
-
self.toggleStore.setEnabled(enabled, metadata: metadata)
|
|
1020
|
-
}
|
|
1021
|
-
|
|
1022
|
-
func rerunProviderDetection() {
|
|
1023
|
-
self.runInitialProviderDetectionIfNeeded(force: true)
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
/// Auto-enable a provider when the user enters a non-empty API token.
|
|
1027
|
-
private func autoEnableProviderIfNeeded(cliName: String) {
|
|
1028
|
-
let toggles = (self.userDefaults.dictionary(forKey: "providerToggles") as? [String: Bool]) ?? [:]
|
|
1029
|
-
guard toggles[cliName] == nil else { return }
|
|
1030
|
-
var updated = toggles
|
|
1031
|
-
updated[cliName] = true
|
|
1032
|
-
self.userDefaults.set(updated, forKey: "providerToggles")
|
|
1033
|
-
self.providerToggleRevision &+= 1
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
// MARK: - Private
|
|
1037
|
-
|
|
1038
|
-
func isCostUsageEffectivelyEnabled(for provider: UsageProvider) -> Bool {
|
|
1039
|
-
self.costUsageEnabled
|
|
1040
|
-
&& ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
private static func effectiveProviderOrder(raw: [String]) -> [UsageProvider] {
|
|
1044
|
-
var seen: Set<UsageProvider> = []
|
|
1045
|
-
var ordered: [UsageProvider] = []
|
|
1046
|
-
|
|
1047
|
-
for rawValue in raw {
|
|
1048
|
-
guard let provider = UsageProvider(rawValue: rawValue) else { continue }
|
|
1049
|
-
guard !seen.contains(provider) else { continue }
|
|
1050
|
-
seen.insert(provider)
|
|
1051
|
-
ordered.append(provider)
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
if ordered.isEmpty {
|
|
1055
|
-
ordered = UsageProvider.allCases
|
|
1056
|
-
seen = Set(ordered)
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
if !seen.contains(.factory), let zaiIndex = ordered.firstIndex(of: .zai) {
|
|
1060
|
-
ordered.insert(.factory, at: zaiIndex)
|
|
1061
|
-
seen.insert(.factory)
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
for provider in UsageProvider.allCases where !seen.contains(provider) {
|
|
1065
|
-
ordered.append(provider)
|
|
1066
|
-
}
|
|
1067
|
-
|
|
1068
|
-
return ordered
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
private func refreshProviderEnablementCacheIfNeeded(
|
|
1072
|
-
metadataByProvider: [UsageProvider: ProviderMetadata])
|
|
1073
|
-
{
|
|
1074
|
-
let revision = self.providerToggleRevision
|
|
1075
|
-
guard revision != self.cachedProviderEnablementRevision else { return }
|
|
1076
|
-
var cache: [UsageProvider: Bool] = [:]
|
|
1077
|
-
for (provider, metadata) in metadataByProvider {
|
|
1078
|
-
cache[provider] = self.toggleStore.isEnabled(metadata: metadata)
|
|
1079
|
-
}
|
|
1080
|
-
self.cachedProviderEnablement = cache
|
|
1081
|
-
self.cachedProviderEnablementRevision = revision
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
|
-
private func runInitialProviderDetectionIfNeeded(force: Bool = false) {
|
|
1085
|
-
guard force || !self.providerDetectionCompleted else { return }
|
|
1086
|
-
guard let codexMeta = ProviderRegistry.shared.metadata[.codex],
|
|
1087
|
-
let claudeMeta = ProviderRegistry.shared.metadata[.claude],
|
|
1088
|
-
let geminiMeta = ProviderRegistry.shared.metadata[.gemini],
|
|
1089
|
-
let antigravityMeta = ProviderRegistry.shared.metadata[.antigravity] else { return }
|
|
1090
|
-
|
|
1091
|
-
LoginShellPathCache.shared.captureOnce { [weak self] _ in
|
|
1092
|
-
Task { @MainActor in
|
|
1093
|
-
await self?.applyProviderDetection(
|
|
1094
|
-
codexMeta: codexMeta,
|
|
1095
|
-
claudeMeta: claudeMeta,
|
|
1096
|
-
geminiMeta: geminiMeta,
|
|
1097
|
-
antigravityMeta: antigravityMeta)
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1101
|
-
|
|
1102
|
-
private func applyProviderDetection(
|
|
1103
|
-
codexMeta: ProviderMetadata,
|
|
1104
|
-
claudeMeta: ProviderMetadata,
|
|
1105
|
-
geminiMeta: ProviderMetadata,
|
|
1106
|
-
antigravityMeta: ProviderMetadata) async
|
|
1107
|
-
{
|
|
1108
|
-
guard !self.providerDetectionCompleted else { return }
|
|
1109
|
-
let codexInstalled = BinaryLocator.resolveCodexBinary() != nil
|
|
1110
|
-
let claudeInstalled = BinaryLocator.resolveClaudeBinary() != nil
|
|
1111
|
-
let geminiInstalled = BinaryLocator.resolveGeminiBinary() != nil
|
|
1112
|
-
let antigravityRunning = await AntigravityStatusProbe.isRunning()
|
|
1113
|
-
|
|
1114
|
-
// If none installed, keep Codex enabled to match previous behavior.
|
|
1115
|
-
let noneInstalled = !codexInstalled && !claudeInstalled && !geminiInstalled && !antigravityRunning
|
|
1116
|
-
let enableCodex = codexInstalled || noneInstalled
|
|
1117
|
-
let enableClaude = claudeInstalled
|
|
1118
|
-
let enableGemini = geminiInstalled
|
|
1119
|
-
let enableAntigravity = antigravityRunning
|
|
1120
|
-
|
|
1121
|
-
self.providerToggleRevision &+= 1
|
|
1122
|
-
self.toggleStore.setEnabled(enableCodex, metadata: codexMeta)
|
|
1123
|
-
self.toggleStore.setEnabled(enableClaude, metadata: claudeMeta)
|
|
1124
|
-
self.toggleStore.setEnabled(enableGemini, metadata: geminiMeta)
|
|
1125
|
-
self.toggleStore.setEnabled(enableAntigravity, metadata: antigravityMeta)
|
|
1126
|
-
self.providerDetectionCompleted = true
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
private func applyTokenCostDefaultIfNeeded() {
|
|
1130
|
-
// Settings are persisted in UserDefaults.standard.
|
|
1131
|
-
guard UserDefaults.standard.object(forKey: "tokenCostUsageEnabled") == nil else { return }
|
|
1132
|
-
|
|
1133
|
-
Task { @MainActor [weak self] in
|
|
1134
|
-
guard let self else { return }
|
|
1135
|
-
let hasSources = await Task.detached(priority: .utility) {
|
|
1136
|
-
Self.hasAnyTokenCostUsageSources()
|
|
1137
|
-
}.value
|
|
1138
|
-
guard hasSources else { return }
|
|
1139
|
-
guard UserDefaults.standard.object(forKey: "tokenCostUsageEnabled") == nil else { return }
|
|
1140
|
-
self.costUsageEnabled = true
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
nonisolated static func hasAnyTokenCostUsageSources(
|
|
1145
|
-
env: [String: String] = ProcessInfo.processInfo.environment,
|
|
1146
|
-
fileManager: FileManager = .default) -> Bool
|
|
1147
|
-
{
|
|
1148
|
-
func hasAnyJsonl(in root: URL) -> Bool {
|
|
1149
|
-
guard fileManager.fileExists(atPath: root.path) else { return false }
|
|
1150
|
-
guard let enumerator = fileManager.enumerator(
|
|
1151
|
-
at: root,
|
|
1152
|
-
includingPropertiesForKeys: [.isRegularFileKey],
|
|
1153
|
-
options: [.skipsHiddenFiles, .skipsPackageDescendants])
|
|
1154
|
-
else { return false }
|
|
1155
|
-
|
|
1156
|
-
for case let url as URL in enumerator where url.pathExtension.lowercased() == "jsonl" {
|
|
1157
|
-
return true
|
|
1158
|
-
}
|
|
1159
|
-
return false
|
|
1160
|
-
}
|
|
1161
|
-
|
|
1162
|
-
let codexRoot: URL = {
|
|
1163
|
-
let raw = env["CODEX_HOME"]?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
1164
|
-
if let raw, !raw.isEmpty {
|
|
1165
|
-
return URL(fileURLWithPath: raw).appendingPathComponent("sessions", isDirectory: true)
|
|
1166
|
-
}
|
|
1167
|
-
return fileManager.homeDirectoryForCurrentUser
|
|
1168
|
-
.appendingPathComponent(".codex", isDirectory: true)
|
|
1169
|
-
.appendingPathComponent("sessions", isDirectory: true)
|
|
1170
|
-
}()
|
|
1171
|
-
if hasAnyJsonl(in: codexRoot) { return true }
|
|
1172
|
-
|
|
1173
|
-
let claudeRoots: [URL] = {
|
|
1174
|
-
if let env = env["CLAUDE_CONFIG_DIR"]?.trimmingCharacters(in: .whitespacesAndNewlines),
|
|
1175
|
-
!env.isEmpty
|
|
1176
|
-
{
|
|
1177
|
-
return env.split(separator: ",").map { part in
|
|
1178
|
-
let raw = String(part).trimmingCharacters(in: .whitespacesAndNewlines)
|
|
1179
|
-
let url = URL(fileURLWithPath: raw)
|
|
1180
|
-
if url.lastPathComponent == "projects" {
|
|
1181
|
-
return url
|
|
1182
|
-
}
|
|
1183
|
-
return url.appendingPathComponent("projects", isDirectory: true)
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
|
-
let home = fileManager.homeDirectoryForCurrentUser
|
|
1188
|
-
return [
|
|
1189
|
-
home.appendingPathComponent(".config/claude/projects", isDirectory: true),
|
|
1190
|
-
home.appendingPathComponent(".claude/projects", isDirectory: true),
|
|
1191
|
-
]
|
|
1192
|
-
}()
|
|
1193
|
-
|
|
1194
|
-
return claudeRoots.contains(where: hasAnyJsonl(in:))
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
private func schedulePersistZaiAPIToken() {
|
|
1198
|
-
self.zaiTokenPersistTask?.cancel()
|
|
1199
|
-
let token = self.zaiAPIToken
|
|
1200
|
-
let tokenStore = self.zaiTokenStore
|
|
1201
|
-
self.zaiTokenPersistTask = Task { @MainActor in
|
|
1202
|
-
do {
|
|
1203
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1204
|
-
} catch {
|
|
1205
|
-
return
|
|
1206
|
-
}
|
|
1207
|
-
guard !Task.isCancelled else { return }
|
|
1208
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1209
|
-
do {
|
|
1210
|
-
try tokenStore.storeToken(token)
|
|
1211
|
-
return nil
|
|
1212
|
-
} catch {
|
|
1213
|
-
return error
|
|
1214
|
-
}
|
|
1215
|
-
}.value
|
|
1216
|
-
if let error {
|
|
1217
|
-
// Keep value in memory; persist best-effort.
|
|
1218
|
-
RunicLog.logger("zai-token-store").error("Failed to persist z.ai token: \(error)")
|
|
1219
|
-
}
|
|
1220
|
-
}
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
private func schedulePersistMiniMaxAPIToken() {
|
|
1224
|
-
self.minimaxTokenPersistTask?.cancel()
|
|
1225
|
-
let token = self.minimaxAPIToken
|
|
1226
|
-
let tokenStore = self.minimaxTokenStore
|
|
1227
|
-
self.minimaxTokenPersistTask = Task { @MainActor in
|
|
1228
|
-
do {
|
|
1229
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1230
|
-
} catch {
|
|
1231
|
-
return
|
|
1232
|
-
}
|
|
1233
|
-
guard !Task.isCancelled else { return }
|
|
1234
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1235
|
-
do {
|
|
1236
|
-
try tokenStore.storeToken(token)
|
|
1237
|
-
return nil
|
|
1238
|
-
} catch {
|
|
1239
|
-
return error
|
|
1240
|
-
}
|
|
1241
|
-
}.value
|
|
1242
|
-
if let error {
|
|
1243
|
-
RunicLog.logger("minimax-token-store").error("Failed to persist MiniMax token: \(error)")
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
|
|
1248
|
-
private func schedulePersistMiniMaxCookieHeader() {
|
|
1249
|
-
self.minimaxCookieHeaderPersistTask?.cancel()
|
|
1250
|
-
let header = self.minimaxCookieHeader
|
|
1251
|
-
let store = self.minimaxCookieHeaderStore
|
|
1252
|
-
self.minimaxCookieHeaderPersistTask = Task { @MainActor in
|
|
1253
|
-
do {
|
|
1254
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1255
|
-
} catch {
|
|
1256
|
-
return
|
|
1257
|
-
}
|
|
1258
|
-
guard !Task.isCancelled else { return }
|
|
1259
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1260
|
-
do {
|
|
1261
|
-
try store.storeHeader(header)
|
|
1262
|
-
return nil
|
|
1263
|
-
} catch {
|
|
1264
|
-
return error
|
|
1265
|
-
}
|
|
1266
|
-
}.value
|
|
1267
|
-
if let error {
|
|
1268
|
-
RunicLog.logger("minimax-cookie-store").error("Failed to persist MiniMax cookie header: \(error)")
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
}
|
|
1272
|
-
|
|
1273
|
-
private func schedulePersistMiniMaxGroupID() {
|
|
1274
|
-
self.minimaxGroupIDPersistTask?.cancel()
|
|
1275
|
-
let groupID = self.minimaxGroupID
|
|
1276
|
-
let groupStore = self.minimaxGroupIDStore
|
|
1277
|
-
self.minimaxGroupIDPersistTask = Task { @MainActor in
|
|
1278
|
-
do {
|
|
1279
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1280
|
-
} catch {
|
|
1281
|
-
return
|
|
1282
|
-
}
|
|
1283
|
-
guard !Task.isCancelled else { return }
|
|
1284
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1285
|
-
do {
|
|
1286
|
-
try groupStore.storeGroupID(groupID)
|
|
1287
|
-
return nil
|
|
1288
|
-
} catch {
|
|
1289
|
-
return error
|
|
1290
|
-
}
|
|
1291
|
-
}.value
|
|
1292
|
-
if let error {
|
|
1293
|
-
RunicLog.logger("minimax-groupid-store").error("Failed to persist MiniMax Group ID: \(error)")
|
|
1294
|
-
}
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
|
|
1298
|
-
private func schedulePersistCopilotAPIToken() {
|
|
1299
|
-
self.copilotTokenPersistTask?.cancel()
|
|
1300
|
-
let token = self.copilotAPIToken
|
|
1301
|
-
let tokenStore = self.copilotTokenStore
|
|
1302
|
-
self.copilotTokenPersistTask = Task { @MainActor in
|
|
1303
|
-
do {
|
|
1304
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1305
|
-
} catch {
|
|
1306
|
-
return
|
|
1307
|
-
}
|
|
1308
|
-
guard !Task.isCancelled else { return }
|
|
1309
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1310
|
-
do {
|
|
1311
|
-
try tokenStore.storeToken(token)
|
|
1312
|
-
return nil
|
|
1313
|
-
} catch {
|
|
1314
|
-
return error
|
|
1315
|
-
}
|
|
1316
|
-
}.value
|
|
1317
|
-
if let error {
|
|
1318
|
-
RunicLog.logger("copilot-token-store").error("Failed to persist Copilot token: \(error)")
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
|
-
private func schedulePersistOpenRouterAPIToken() {
|
|
1324
|
-
self.openRouterTokenPersistTask?.cancel()
|
|
1325
|
-
let token = self.openRouterAPIToken
|
|
1326
|
-
let tokenStore = self.openRouterTokenStore
|
|
1327
|
-
self.openRouterTokenPersistTask = Task { @MainActor in
|
|
1328
|
-
do {
|
|
1329
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1330
|
-
} catch {
|
|
1331
|
-
return
|
|
1332
|
-
}
|
|
1333
|
-
guard !Task.isCancelled else { return }
|
|
1334
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1335
|
-
do {
|
|
1336
|
-
try tokenStore.storeToken(token)
|
|
1337
|
-
return nil
|
|
1338
|
-
} catch {
|
|
1339
|
-
return error
|
|
1340
|
-
}
|
|
1341
|
-
}.value
|
|
1342
|
-
if let error {
|
|
1343
|
-
RunicLog.logger("openrouter-token-store").error("Failed to persist OpenRouter token: \(error)")
|
|
1344
|
-
}
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
|
-
private func schedulePersistGroqAPIToken() {
|
|
1349
|
-
self.groqTokenPersistTask?.cancel()
|
|
1350
|
-
let token = self.groqAPIToken
|
|
1351
|
-
let tokenStore = self.groqTokenStore
|
|
1352
|
-
self.groqTokenPersistTask = Task { @MainActor in
|
|
1353
|
-
do {
|
|
1354
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1355
|
-
} catch {
|
|
1356
|
-
return
|
|
1357
|
-
}
|
|
1358
|
-
guard !Task.isCancelled else { return }
|
|
1359
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1360
|
-
do {
|
|
1361
|
-
try tokenStore.storeToken(token)
|
|
1362
|
-
return nil
|
|
1363
|
-
} catch {
|
|
1364
|
-
return error
|
|
1365
|
-
}
|
|
1366
|
-
}.value
|
|
1367
|
-
if let error {
|
|
1368
|
-
RunicLog.logger("groq-token-store").error("Failed to persist Groq token: \(error)")
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
1371
|
-
}
|
|
1372
|
-
|
|
1373
|
-
private func schedulePersistDeepSeekAPIToken() {
|
|
1374
|
-
self.deepSeekTokenPersistTask?.cancel()
|
|
1375
|
-
let token = self.deepSeekAPIToken
|
|
1376
|
-
let tokenStore = self.deepSeekTokenStore
|
|
1377
|
-
self.deepSeekTokenPersistTask = Task { @MainActor in
|
|
1378
|
-
do {
|
|
1379
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1380
|
-
} catch {
|
|
1381
|
-
return
|
|
1382
|
-
}
|
|
1383
|
-
guard !Task.isCancelled else { return }
|
|
1384
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1385
|
-
do {
|
|
1386
|
-
try tokenStore.storeToken(token)
|
|
1387
|
-
return nil
|
|
1388
|
-
} catch {
|
|
1389
|
-
return error
|
|
1390
|
-
}
|
|
1391
|
-
}.value
|
|
1392
|
-
if let error {
|
|
1393
|
-
RunicLog.logger("deepseek-token-store").error("Failed to persist DeepSeek token: \(error)")
|
|
1394
|
-
}
|
|
1395
|
-
}
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
private func schedulePersistFireworksAPIToken() {
|
|
1399
|
-
self.fireworksTokenPersistTask?.cancel()
|
|
1400
|
-
let token = self.fireworksAPIToken
|
|
1401
|
-
let tokenStore = self.fireworksTokenStore
|
|
1402
|
-
self.fireworksTokenPersistTask = Task { @MainActor in
|
|
1403
|
-
do {
|
|
1404
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1405
|
-
} catch {
|
|
1406
|
-
return
|
|
1407
|
-
}
|
|
1408
|
-
guard !Task.isCancelled else { return }
|
|
1409
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1410
|
-
do {
|
|
1411
|
-
try tokenStore.storeToken(token)
|
|
1412
|
-
return nil
|
|
1413
|
-
} catch {
|
|
1414
|
-
return error
|
|
1415
|
-
}
|
|
1416
|
-
}.value
|
|
1417
|
-
if let error {
|
|
1418
|
-
RunicLog.logger("fireworks-token-store").error("Failed to persist Fireworks token: \(error)")
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
|
-
}
|
|
1422
|
-
|
|
1423
|
-
private func schedulePersistMistralAPIToken() {
|
|
1424
|
-
self.mistralTokenPersistTask?.cancel()
|
|
1425
|
-
let token = self.mistralAPIToken
|
|
1426
|
-
let tokenStore = self.mistralTokenStore
|
|
1427
|
-
self.mistralTokenPersistTask = Task { @MainActor in
|
|
1428
|
-
do {
|
|
1429
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1430
|
-
} catch {
|
|
1431
|
-
return
|
|
1432
|
-
}
|
|
1433
|
-
guard !Task.isCancelled else { return }
|
|
1434
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1435
|
-
do {
|
|
1436
|
-
try tokenStore.storeToken(token)
|
|
1437
|
-
return nil
|
|
1438
|
-
} catch {
|
|
1439
|
-
return error
|
|
1440
|
-
}
|
|
1441
|
-
}.value
|
|
1442
|
-
if let error {
|
|
1443
|
-
RunicLog.logger("mistral-token-store").error("Failed to persist Mistral token: \(error)")
|
|
1444
|
-
}
|
|
1445
|
-
}
|
|
1446
|
-
}
|
|
1447
|
-
|
|
1448
|
-
private func schedulePersistPerplexityAPIToken() {
|
|
1449
|
-
self.perplexityTokenPersistTask?.cancel()
|
|
1450
|
-
let token = self.perplexityAPIToken
|
|
1451
|
-
let tokenStore = self.perplexityTokenStore
|
|
1452
|
-
self.perplexityTokenPersistTask = Task { @MainActor in
|
|
1453
|
-
do {
|
|
1454
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1455
|
-
} catch {
|
|
1456
|
-
return
|
|
1457
|
-
}
|
|
1458
|
-
guard !Task.isCancelled else { return }
|
|
1459
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1460
|
-
do {
|
|
1461
|
-
try tokenStore.storeToken(token)
|
|
1462
|
-
return nil
|
|
1463
|
-
} catch {
|
|
1464
|
-
return error
|
|
1465
|
-
}
|
|
1466
|
-
}.value
|
|
1467
|
-
if let error {
|
|
1468
|
-
RunicLog.logger("perplexity-token-store").error("Failed to persist Perplexity token: \(error)")
|
|
1469
|
-
}
|
|
1470
|
-
}
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
private func schedulePersistKimiAPIToken() {
|
|
1474
|
-
self.kimiTokenPersistTask?.cancel()
|
|
1475
|
-
let token = self.kimiAPIToken
|
|
1476
|
-
let tokenStore = self.kimiTokenStore
|
|
1477
|
-
self.kimiTokenPersistTask = Task { @MainActor in
|
|
1478
|
-
do {
|
|
1479
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1480
|
-
} catch {
|
|
1481
|
-
return
|
|
1482
|
-
}
|
|
1483
|
-
guard !Task.isCancelled else { return }
|
|
1484
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1485
|
-
do {
|
|
1486
|
-
try tokenStore.storeToken(token)
|
|
1487
|
-
return nil
|
|
1488
|
-
} catch {
|
|
1489
|
-
return error
|
|
1490
|
-
}
|
|
1491
|
-
}.value
|
|
1492
|
-
if let error {
|
|
1493
|
-
RunicLog.logger("kimi-token-store").error("Failed to persist Kimi token: \(error)")
|
|
1494
|
-
}
|
|
1495
|
-
}
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
private func schedulePersistAuggieAPIToken() {
|
|
1499
|
-
self.auggieTokenPersistTask?.cancel()
|
|
1500
|
-
let token = self.auggieAPIToken
|
|
1501
|
-
let tokenStore = self.auggieTokenStore
|
|
1502
|
-
self.auggieTokenPersistTask = Task { @MainActor in
|
|
1503
|
-
do {
|
|
1504
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1505
|
-
} catch {
|
|
1506
|
-
return
|
|
1507
|
-
}
|
|
1508
|
-
guard !Task.isCancelled else { return }
|
|
1509
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1510
|
-
do {
|
|
1511
|
-
try tokenStore.storeToken(token)
|
|
1512
|
-
return nil
|
|
1513
|
-
} catch {
|
|
1514
|
-
return error
|
|
1515
|
-
}
|
|
1516
|
-
}.value
|
|
1517
|
-
if let error {
|
|
1518
|
-
RunicLog.logger("auggie-token-store").error("Failed to persist Auggie token: \(error)")
|
|
1519
|
-
}
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
|
-
private func schedulePersistTogetherAPIToken() {
|
|
1524
|
-
self.togetherTokenPersistTask?.cancel()
|
|
1525
|
-
let token = self.togetherAPIToken
|
|
1526
|
-
let tokenStore = self.togetherTokenStore
|
|
1527
|
-
self.togetherTokenPersistTask = Task { @MainActor in
|
|
1528
|
-
do {
|
|
1529
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1530
|
-
} catch {
|
|
1531
|
-
return
|
|
1532
|
-
}
|
|
1533
|
-
guard !Task.isCancelled else { return }
|
|
1534
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1535
|
-
do {
|
|
1536
|
-
try tokenStore.storeToken(token)
|
|
1537
|
-
return nil
|
|
1538
|
-
} catch {
|
|
1539
|
-
return error
|
|
1540
|
-
}
|
|
1541
|
-
}.value
|
|
1542
|
-
if let error {
|
|
1543
|
-
RunicLog.logger("together-token-store").error("Failed to persist Together token: \(error)")
|
|
1544
|
-
}
|
|
1545
|
-
}
|
|
1546
|
-
}
|
|
1547
|
-
|
|
1548
|
-
private func schedulePersistCohereAPIToken() {
|
|
1549
|
-
self.cohereTokenPersistTask?.cancel()
|
|
1550
|
-
let token = self.cohereAPIToken
|
|
1551
|
-
let tokenStore = self.cohereTokenStore
|
|
1552
|
-
self.cohereTokenPersistTask = Task { @MainActor in
|
|
1553
|
-
do {
|
|
1554
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1555
|
-
} catch {
|
|
1556
|
-
return
|
|
1557
|
-
}
|
|
1558
|
-
guard !Task.isCancelled else { return }
|
|
1559
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1560
|
-
do {
|
|
1561
|
-
try tokenStore.storeToken(token)
|
|
1562
|
-
return nil
|
|
1563
|
-
} catch {
|
|
1564
|
-
return error
|
|
1565
|
-
}
|
|
1566
|
-
}.value
|
|
1567
|
-
if let error {
|
|
1568
|
-
RunicLog.logger("cohere-token-store").error("Failed to persist Cohere token: \(error)")
|
|
1569
|
-
}
|
|
1570
|
-
}
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
|
-
private func schedulePersistXAiAPIToken() {
|
|
1574
|
-
self.xaiTokenPersistTask?.cancel()
|
|
1575
|
-
let token = self.xaiAPIToken
|
|
1576
|
-
let tokenStore = self.xaiTokenStore
|
|
1577
|
-
self.xaiTokenPersistTask = Task { @MainActor in
|
|
1578
|
-
do {
|
|
1579
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1580
|
-
} catch {
|
|
1581
|
-
return
|
|
1582
|
-
}
|
|
1583
|
-
guard !Task.isCancelled else { return }
|
|
1584
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1585
|
-
do {
|
|
1586
|
-
try tokenStore.storeToken(token)
|
|
1587
|
-
return nil
|
|
1588
|
-
} catch {
|
|
1589
|
-
return error
|
|
1590
|
-
}
|
|
1591
|
-
}.value
|
|
1592
|
-
if let error {
|
|
1593
|
-
RunicLog.logger("xai-token-store").error("Failed to persist xAI token: \(error)")
|
|
1594
|
-
}
|
|
1595
|
-
}
|
|
1596
|
-
}
|
|
1597
|
-
|
|
1598
|
-
private func schedulePersistCerebrasAPIToken() {
|
|
1599
|
-
self.cerebrasTokenPersistTask?.cancel()
|
|
1600
|
-
let token = self.cerebrasAPIToken
|
|
1601
|
-
let tokenStore = self.cerebrasTokenStore
|
|
1602
|
-
self.cerebrasTokenPersistTask = Task { @MainActor in
|
|
1603
|
-
do {
|
|
1604
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1605
|
-
} catch {
|
|
1606
|
-
return
|
|
1607
|
-
}
|
|
1608
|
-
guard !Task.isCancelled else { return }
|
|
1609
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1610
|
-
do {
|
|
1611
|
-
try tokenStore.storeToken(token)
|
|
1612
|
-
return nil
|
|
1613
|
-
} catch {
|
|
1614
|
-
return error
|
|
1615
|
-
}
|
|
1616
|
-
}.value
|
|
1617
|
-
if let error {
|
|
1618
|
-
RunicLog.logger("cerebras-token-store").error("Failed to persist Cerebras token: \(error)")
|
|
1619
|
-
}
|
|
1620
|
-
}
|
|
1621
|
-
}
|
|
1622
|
-
|
|
1623
|
-
private func schedulePersistSambaNovaAPIToken() {
|
|
1624
|
-
self.sambaNovaTokenPersistTask?.cancel()
|
|
1625
|
-
let token = self.sambaNovaAPIToken
|
|
1626
|
-
let tokenStore = self.sambaNovaTokenStore
|
|
1627
|
-
self.sambaNovaTokenPersistTask = Task { @MainActor in
|
|
1628
|
-
do {
|
|
1629
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1630
|
-
} catch {
|
|
1631
|
-
return
|
|
1632
|
-
}
|
|
1633
|
-
guard !Task.isCancelled else { return }
|
|
1634
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1635
|
-
do {
|
|
1636
|
-
try tokenStore.storeToken(token)
|
|
1637
|
-
return nil
|
|
1638
|
-
} catch {
|
|
1639
|
-
return error
|
|
1640
|
-
}
|
|
1641
|
-
}.value
|
|
1642
|
-
if let error {
|
|
1643
|
-
RunicLog.logger("sambanova-token-store").error("Failed to persist SambaNova token: \(error)")
|
|
1644
|
-
}
|
|
1645
|
-
}
|
|
1646
|
-
}
|
|
1647
|
-
|
|
1648
|
-
private func schedulePersistAzureOpenAIAPIToken() {
|
|
1649
|
-
self.azureOpenAITokenPersistTask?.cancel()
|
|
1650
|
-
let token = self.azureOpenAIAPIToken
|
|
1651
|
-
let tokenStore = self.azureOpenAITokenStore
|
|
1652
|
-
self.azureOpenAITokenPersistTask = Task { @MainActor in
|
|
1653
|
-
do {
|
|
1654
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1655
|
-
} catch {
|
|
1656
|
-
return
|
|
1657
|
-
}
|
|
1658
|
-
guard !Task.isCancelled else { return }
|
|
1659
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1660
|
-
do {
|
|
1661
|
-
try tokenStore.storeToken(token)
|
|
1662
|
-
return nil
|
|
1663
|
-
} catch {
|
|
1664
|
-
return error
|
|
1665
|
-
}
|
|
1666
|
-
}.value
|
|
1667
|
-
if let error {
|
|
1668
|
-
RunicLog.logger("azure-openai-token-store")
|
|
1669
|
-
.error("Failed to persist Azure OpenAI token: \(error)")
|
|
1670
|
-
}
|
|
1671
|
-
}
|
|
1672
|
-
}
|
|
1673
|
-
|
|
1674
|
-
private func schedulePersistQwenAPIToken() {
|
|
1675
|
-
self.qwenTokenPersistTask?.cancel()
|
|
1676
|
-
let token = self.qwenAPIToken
|
|
1677
|
-
let tokenStore = self.qwenTokenStore
|
|
1678
|
-
self.qwenTokenPersistTask = Task { @MainActor in
|
|
1679
|
-
do {
|
|
1680
|
-
try await Task.sleep(nanoseconds: 350_000_000)
|
|
1681
|
-
} catch {
|
|
1682
|
-
return
|
|
1683
|
-
}
|
|
1684
|
-
guard !Task.isCancelled else { return }
|
|
1685
|
-
let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
|
|
1686
|
-
do {
|
|
1687
|
-
try tokenStore.storeToken(token)
|
|
1688
|
-
return nil
|
|
1689
|
-
} catch {
|
|
1690
|
-
return error
|
|
1691
|
-
}
|
|
1692
|
-
}.value
|
|
1693
|
-
if let error {
|
|
1694
|
-
RunicLog.logger("qwen-token-store").error("Failed to persist Qwen token: \(error)")
|
|
1695
|
-
}
|
|
1696
|
-
}
|
|
1697
|
-
}
|
|
1698
|
-
}
|
|
1699
|
-
|
|
1700
|
-
enum LaunchAtLoginManager {
|
|
1701
|
-
@MainActor
|
|
1702
|
-
static func setEnabled(_ enabled: Bool) {
|
|
1703
|
-
guard #available(macOS 13, *) else { return }
|
|
1704
|
-
let service = SMAppService.mainApp
|
|
1705
|
-
if enabled {
|
|
1706
|
-
try? service.register()
|
|
1707
|
-
} else {
|
|
1708
|
-
try? service.unregister()
|
|
1709
|
-
}
|
|
1710
|
-
}
|
|
1711
|
-
}
|