@sriinnu/runic 2.0.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 +256 -0
- package/LICENSE +373 -21
- package/README.md +96 -89
- 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/RunicTypographyiOS.swift +0 -24
- 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 -117
- package/Sources/Runic/Controllers/StatusItemController+Actions.swift +0 -670
- package/Sources/Runic/Controllers/StatusItemController+Animation.swift +0 -519
- package/Sources/Runic/Controllers/StatusItemController+ChartSubmenus.swift +0 -824
- package/Sources/Runic/Controllers/StatusItemController+CustomProviders.swift +0 -90
- package/Sources/Runic/Controllers/StatusItemController+Menu.swift +0 -1412
- package/Sources/Runic/Controllers/StatusItemController+MenuCards.swift +0 -339
- package/Sources/Runic/Controllers/StatusItemController+MenuHelpers.swift +0 -423
- package/Sources/Runic/Controllers/StatusItemController.swift +0 -360
- package/Sources/Runic/Core/BudgetNotificationManager.swift +0 -81
- 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 -1222
- package/Sources/Runic/Core/Rendering/IconView.swift +0 -122
- 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/RunicTypography.swift +0 -206
- package/Sources/Runic/Core/Stores/AuggieTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/AzureOpenAITokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/CerebrasTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/CohereTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/CopilotTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/CustomProviderStore.swift +0 -158
- package/Sources/Runic/Core/Stores/DeepSeekTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/FireworksTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/GroqTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/KimiTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/MiniMaxCookieHeaderStore.swift +0 -117
- package/Sources/Runic/Core/Stores/MiniMaxGroupIDStore.swift +0 -117
- package/Sources/Runic/Core/Stores/MiniMaxTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/MistralTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/OpenRouterTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/PerplexityTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/ProviderToggleStore.swift +0 -30
- package/Sources/Runic/Core/Stores/QwenTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/SambaNovaTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/SettingsStore.swift +0 -1749
- package/Sources/Runic/Core/Stores/TogetherTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/UsageStore+Accessors.swift +0 -33
- 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 -3631
- package/Sources/Runic/Core/Stores/XAITokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/ZaiTokenStore.swift +0 -117
- package/Sources/Runic/Core/UsageExporter.swift +0 -197
- 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 -51
- 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/Fonts/Caveat-Bold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/Caveat-Regular.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/FiraCode-Bold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/FiraCode-Light.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/FiraCode-Medium.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/FiraCode-Regular.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/FiraCode-SemiBold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/IBMPlexMono-Bold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/IBMPlexMono-Medium.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/IBMPlexMono-Regular.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/IBMPlexMono-SemiBold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/Inconsolata-Bold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/Inconsolata-Medium.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/Inconsolata-Regular.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/Inconsolata-SemiBold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/JetBrainsMono-Bold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/JetBrainsMono-Medium.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/JetBrainsMono-Regular.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/JetBrainsMono-SemiBold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/SpaceMono-Bold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/SpaceMono-Regular.ttf +0 -0
- 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 -367
- package/Sources/Runic/SessionQuotaNotifications.swift +0 -58
- package/Sources/Runic/UsagePaceText.swift +0 -52
- package/Sources/Runic/UsageProgressBar.swift +0 -228
- package/Sources/Runic/Utilities/DisplayLink.swift +0 -96
- package/Sources/Runic/Utilities/LoadingPattern.swift +0 -62
- package/Sources/Runic/Utilities/PerformanceConstants.swift +0 -85
- package/Sources/Runic/Views/Menu/AlertsMenuView.swift +0 -254
- 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 -311
- package/Sources/Runic/Views/Menu/HeroStatCardsMenuView.swift +0 -231
- package/Sources/Runic/Views/Menu/HourlyActivityChartMenuView.swift +0 -228
- package/Sources/Runic/Views/Menu/InlineUsageChartView.swift +0 -157
- package/Sources/Runic/Views/Menu/MenuCardEntranceModifier.swift +0 -63
- package/Sources/Runic/Views/Menu/MenuCardSidebarView.swift +0 -248
- package/Sources/Runic/Views/Menu/MenuCardSkeletonView.swift +0 -104
- package/Sources/Runic/Views/Menu/MenuCardView.swift +0 -1889
- package/Sources/Runic/Views/Menu/MenuContent.swift +0 -153
- package/Sources/Runic/Views/Menu/MenuDescriptor.swift +0 -371
- package/Sources/Runic/Views/Menu/MenuHighlightStyle.swift +0 -35
- package/Sources/Runic/Views/Menu/ModelBreakdownMenuView.swift +0 -241
- package/Sources/Runic/Views/Menu/OverviewMenuView.swift +0 -281
- package/Sources/Runic/Views/Menu/ProjectBreakdownMenuView.swift +0 -214
- package/Sources/Runic/Views/Menu/ProjectBudgetMenuView.swift +0 -220
- package/Sources/Runic/Views/Menu/ProviderTabBarView.swift +0 -86
- package/Sources/Runic/Views/Menu/SubscriptionUtilizationChartMenuView.swift +0 -214
- package/Sources/Runic/Views/Menu/UsageBreakdownChartMenuView.swift +0 -398
- package/Sources/Runic/Views/Menu/UsageHeatmapMenuView.swift +0 -231
- package/Sources/Runic/Views/Menu/UsageTimelineChartMenuView.swift +0 -369
- package/Sources/Runic/Views/Menu/UsageWindowComparisonChartMenuView.swift +0 -191
- package/Sources/Runic/Views/Menu/WeeklyActivityChartMenuView.swift +0 -132
- package/Sources/Runic/Views/Performance/PerformanceDashboardView.swift +0 -621
- package/Sources/Runic/Views/Preferences/LiquidComponents.swift +0 -306
- 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 -418
- package/Sources/Runic/Views/Preferences/PreferencesAnalyticsPane.swift +0 -637
- 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 -321
- package/Sources/Runic/Views/Preferences/PreferencesDebugPane.swift +0 -469
- package/Sources/Runic/Views/Preferences/PreferencesGeneralPane.swift +0 -250
- package/Sources/Runic/Views/Preferences/PreferencesHelpPane.swift +0 -50
- package/Sources/Runic/Views/Preferences/PreferencesIntegrationsPane.swift +0 -572
- package/Sources/Runic/Views/Preferences/PreferencesPerformancePane.swift +0 -291
- package/Sources/Runic/Views/Preferences/PreferencesProvidersPane.swift +0 -3480
- package/Sources/Runic/Views/Preferences/PreferencesSelection.swift +0 -29
- package/Sources/Runic/Views/Preferences/PreferencesSyncPane.swift +0 -61
- package/Sources/Runic/Views/Preferences/PreferencesView.swift +0 -213
- package/Sources/Runic/Views/Rating/QualityRatingView.swift +0 -238
- package/Sources/Runic/Views/Team/TeamDashboardView.swift +0 -376
- package/Sources/Runic/Views/Team/TeamInviteSheet.swift +0 -175
- package/Sources/Runic/Views/Team/TeamManagementView.swift +0 -762
- package/Sources/Runic/Views/Team/TeamMemberRow.swift +0 -181
- package/Sources/RunicCLI/CLIEntry.swift +0 -983
- package/Sources/RunicCLI/CLIRenderer.swift +0 -87
- package/Sources/RunicCLI/Commands/EnhancedUsageCommand.swift +0 -588
- package/Sources/RunicCLI/Commands/ModelsCommand.swift +0 -363
- package/Sources/RunicCLI/Commands/ProjectsCommand.swift +0 -453
- package/Sources/RunicCLI/Commands/ResetCommand.swift +0 -430
- package/Sources/RunicCLI/Commands/UsageLedgerSourceFactory.swift +0 -167
- 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 -268
- package/Sources/RunicCore/CustomProviders/GenericProviderFetcher.swift +0 -631
- package/Sources/RunicCore/CustomProviders/ProviderTemplates.swift +0 -444
- 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 -370
- 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 -426
- package/Sources/RunicCore/Policy/UsagePolicyEngine.swift +0 -178
- package/Sources/RunicCore/ProjectBudgetStore.swift +0 -102
- package/Sources/RunicCore/ProviderCostSnapshot.swift +0 -29
- package/Sources/RunicCore/Providers/Antigravity/AntigravityProviderDescriptor.swift +0 -68
- 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 -164
- 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 -209
- package/Sources/RunicCore/Providers/Claude/ClaudeStatusProbe.swift +0 -654
- package/Sources/RunicCore/Providers/Claude/ClaudeUsageDataSource.swift +0 -30
- 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 -245
- package/Sources/RunicCore/Providers/Codex/CodexStatusProbe.swift +0 -125
- package/Sources/RunicCore/Providers/Codex/CodexUsageDataSource.swift +0 -26
- package/Sources/RunicCore/Providers/Codex/CodexWebDashboardStrategy.swift +0 -183
- 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 -117
- package/Sources/RunicCore/Providers/Copilot/CopilotProviderDescriptor.swift +0 -100
- package/Sources/RunicCore/Providers/Copilot/CopilotUsageFetcher.swift +0 -293
- package/Sources/RunicCore/Providers/Copilot/CopilotVSCodeTokenReader.swift +0 -385
- package/Sources/RunicCore/Providers/Cursor/CursorProviderDescriptor.swift +0 -67
- 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 -67
- 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 -67
- package/Sources/RunicCore/Providers/Gemini/GeminiStatusProbe.swift +0 -839
- 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 -97
- 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 -216
- 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 -86
- package/Sources/RunicCore/Providers/Qwen/QwenSettingsReader.swift +0 -30
- package/Sources/RunicCore/Providers/Qwen/QwenUsageStats.swift +0 -328
- 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 -74
- package/Sources/RunicCore/Providers/Zai/ZaiSettingsReader.swift +0 -41
- package/Sources/RunicCore/Providers/Zai/ZaiUsageStats.swift +0 -745
- package/Sources/RunicCore/Sync/BackgroundSyncManager.swift +0 -384
- package/Sources/RunicCore/Sync/SyncConflictResolver.swift +0 -307
- package/Sources/RunicCore/Sync/SyncProtocol.swift +0 -287
- package/Sources/RunicCore/Sync/SyncRecord.swift +0 -402
- package/Sources/RunicCore/Sync/SyncUsageExample.swift +0 -288
- package/Sources/RunicCore/Sync/TeamSyncRecords.swift +0 -768
- package/Sources/RunicCore/Sync/iCloudSyncEngine.swift +0 -338
- package/Sources/RunicCore/Team/TeamModels.swift +0 -584
- package/Sources/RunicCore/Team/TeamShowbackExporter.swift +0 -495
- package/Sources/RunicCore/Team/TeamStore.swift +0 -809
- 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 -441
- package/Sources/RunicCore/UsageLedger/CodexUsageLogSource.swift +0 -502
- package/Sources/RunicCore/UsageLedger/LedgerCache.swift +0 -161
- package/Sources/RunicCore/UsageLedger/OTelGenAILedgerAdapter.swift +0 -550
- package/Sources/RunicCore/UsageLedger/UsageLedger.swift +0 -29
- package/Sources/RunicCore/UsageLedger/UsageLedgerAggregator.swift +0 -675
- package/Sources/RunicCore/UsageLedger/UsageLedgerInsightsAdvisor.swift +0 -209
- package/Sources/RunicCore/UsageLedger/UsageLedgerModels.swift +0 -417
- package/Sources/RunicCore/UsageLedger/UsageLedgerProjectIdentity.swift +0 -284
- 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 -48
- package/Tests/RunicTests/BrowserCookieOrderLabelTests.swift +0 -21
- package/Tests/RunicTests/CLIArgumentParsingTests.swift +0 -69
- package/Tests/RunicTests/CLICostTests.swift +0 -64
- package/Tests/RunicTests/CLIProviderSelectionTests.swift +0 -21
- package/Tests/RunicTests/CLISnapshotTests.swift +0 -71
- package/Tests/RunicTests/CLIWebFallbackTests.swift +0 -57
- package/Tests/RunicTests/ClaudeOAuthTests.swift +0 -163
- package/Tests/RunicTests/ClaudeResilienceTests.swift +0 -29
- package/Tests/RunicTests/ClaudeUsageTests.swift +0 -369
- package/Tests/RunicTests/CodexOAuthTests.swift +0 -121
- package/Tests/RunicTests/CodexUsageLogSourceTests.swift +0 -80
- package/Tests/RunicTests/CopilotTokenResolverTests.swift +0 -74
- package/Tests/RunicTests/CopilotVSCodeTokenReaderTests.swift +0 -74
- package/Tests/RunicTests/CostUsageDecodingTests.swift +0 -392
- package/Tests/RunicTests/CostUsagePricingTests.swift +0 -48
- package/Tests/RunicTests/CostUsageScannerTests.swift +0 -698
- package/Tests/RunicTests/CursorStatusProbeTests.swift +0 -322
- package/Tests/RunicTests/FactoryStatusProbeTests.swift +0 -67
- package/Tests/RunicTests/GeminiAPITestHelpers.swift +0 -94
- package/Tests/RunicTests/GeminiLoginAlertTests.swift +0 -27
- package/Tests/RunicTests/GeminiStatusProbeAPITests.swift +0 -283
- package/Tests/RunicTests/GeminiStatusProbePlanTests.swift +0 -279
- package/Tests/RunicTests/GeminiStatusProbeTests.swift +0 -232
- package/Tests/RunicTests/GeminiTestEnvironment.swift +0 -87
- package/Tests/RunicTests/GoogleWorkspaceStatusTests.swift +0 -72
- package/Tests/RunicTests/InstallOriginTests.swift +0 -17
- package/Tests/RunicTests/KeyboardShortcutsBundleTests.swift +0 -9
- package/Tests/RunicTests/LiveAccountTests.swift +0 -24
- package/Tests/RunicTests/LoadingPatternTests.swift +0 -34
- package/Tests/RunicTests/MenuCardModelTests.swift +0 -544
- package/Tests/RunicTests/MiniMaxCookieHeaderStoreTestSupport.swift +0 -11
- package/Tests/RunicTests/MiniMaxGroupIDStoreTestSupport.swift +0 -11
- package/Tests/RunicTests/MiniMaxParsingTests.swift +0 -67
- package/Tests/RunicTests/MiniMaxTokenStoreTestSupport.swift +0 -11
- package/Tests/RunicTests/OTelGenAILedgerAdapterTests.swift +0 -110
- package/Tests/RunicTests/OpenAIDashboardBrowserCookieImporterTests.swift +0 -16
- package/Tests/RunicTests/OpenAIDashboardFetcherCreditsWaitTests.swift +0 -74
- package/Tests/RunicTests/OpenAIDashboardOffscreenHostTests.swift +0 -26
- package/Tests/RunicTests/OpenAIDashboardParserTests.swift +0 -133
- package/Tests/RunicTests/OpenAIWebAccountSwitchTests.swift +0 -64
- package/Tests/RunicTests/OpenRouterTokenStoreTestSupport.swift +0 -131
- package/Tests/RunicTests/PathBuilderTests.swift +0 -236
- package/Tests/RunicTests/ProviderFetchPipelineTests.swift +0 -159
- package/Tests/RunicTests/ProviderIconResourcesTests.swift +0 -37
- package/Tests/RunicTests/ProviderMetadataStatusLinkTests.swift +0 -15
- package/Tests/RunicTests/ProviderRegistryTests.swift +0 -29
- package/Tests/RunicTests/ProviderSettingsDescriptorTests.swift +0 -236
- package/Tests/RunicTests/ProviderToggleStoreTests.swift +0 -50
- package/Tests/RunicTests/RunicTests.swift +0 -119
- package/Tests/RunicTests/SessionQuotaNotificationLogicTests.swift +0 -35
- package/Tests/RunicTests/SettingsStoreTests.swift +0 -265
- package/Tests/RunicTests/StatusItemAnimationTests.swift +0 -54
- package/Tests/RunicTests/StatusMenuTests.swift +0 -475
- package/Tests/RunicTests/StatusProbeTests.swift +0 -376
- package/Tests/RunicTests/SubprocessRunnerTests.swift +0 -18
- package/Tests/RunicTests/SubscriptionDetectionTests.swift +0 -64
- package/Tests/RunicTests/TTYCommandRunnerTests.swift +0 -147
- package/Tests/RunicTests/TTYIntegrationTests.swift +0 -41
- package/Tests/RunicTests/TeamShowbackExporterTests.swift +0 -157
- package/Tests/RunicTests/TextParsingTests.swift +0 -11
- package/Tests/RunicTests/UsageFormatterTests.swift +0 -111
- package/Tests/RunicTests/UsageLedgerAnomalyDetectionTests.swift +0 -170
- package/Tests/RunicTests/UsageLedgerForecastTests.swift +0 -211
- package/Tests/RunicTests/UsageLedgerInsightsAdvisorTests.swift +0 -81
- package/Tests/RunicTests/UsageLedgerProjectNameTests.swift +0 -168
- package/Tests/RunicTests/UsagePaceTests.swift +0 -76
- package/Tests/RunicTests/UsagePaceTextTests.swift +0 -108
- package/Tests/RunicTests/UsagePolicyEngineTests.swift +0 -89
- package/Tests/RunicTests/WidgetSnapshotTests.swift +0 -43
- package/Tests/RunicTests/ZaiProviderTests.swift +0 -59
- package/Tests/RunicTests/ZaiTokenStoreTestSupport.swift +0 -9
- package/TestsLinux/PlatformGatingTests.swift +0 -46
- package/appcast.xml +0 -104
- 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/runic.svg +0 -15
- package/version.env +0 -2
|
@@ -1,745 +0,0 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
#if canImport(FoundationNetworking)
|
|
3
|
-
import FoundationNetworking
|
|
4
|
-
#endif
|
|
5
|
-
|
|
6
|
-
// MARK: - Enums
|
|
7
|
-
|
|
8
|
-
/// Z.ai usage limit types from the API
|
|
9
|
-
public enum ZaiLimitType: String, Sendable {
|
|
10
|
-
case timeLimit = "TIME_LIMIT"
|
|
11
|
-
case tokensLimit = "TOKENS_LIMIT"
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/// Z.ai usage limit unit types
|
|
15
|
-
public enum ZaiLimitUnit: Int, Sendable {
|
|
16
|
-
case unknown = 0
|
|
17
|
-
case days = 1
|
|
18
|
-
case hours = 3
|
|
19
|
-
case minutes = 5
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// MARK: - Quota limit models
|
|
23
|
-
|
|
24
|
-
/// A single limit entry from the z.ai API
|
|
25
|
-
public struct ZaiLimitEntry: Sendable {
|
|
26
|
-
public let type: ZaiLimitType
|
|
27
|
-
public let unit: ZaiLimitUnit
|
|
28
|
-
public let number: Int
|
|
29
|
-
public let usage: Int
|
|
30
|
-
public let currentValue: Int
|
|
31
|
-
public let remaining: Int
|
|
32
|
-
public let percentage: Double
|
|
33
|
-
public let usageDetails: [ZaiUsageDetail]
|
|
34
|
-
public let nextResetTime: Date?
|
|
35
|
-
|
|
36
|
-
public init(
|
|
37
|
-
type: ZaiLimitType,
|
|
38
|
-
unit: ZaiLimitUnit,
|
|
39
|
-
number: Int,
|
|
40
|
-
usage: Int,
|
|
41
|
-
currentValue: Int,
|
|
42
|
-
remaining: Int,
|
|
43
|
-
percentage: Double,
|
|
44
|
-
usageDetails: [ZaiUsageDetail],
|
|
45
|
-
nextResetTime: Date?)
|
|
46
|
-
{
|
|
47
|
-
self.type = type
|
|
48
|
-
self.unit = unit
|
|
49
|
-
self.number = number
|
|
50
|
-
self.usage = usage
|
|
51
|
-
self.currentValue = currentValue
|
|
52
|
-
self.remaining = remaining
|
|
53
|
-
self.percentage = percentage
|
|
54
|
-
self.usageDetails = usageDetails
|
|
55
|
-
self.nextResetTime = nextResetTime
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
extension ZaiLimitEntry {
|
|
60
|
-
public var usedPercent: Double {
|
|
61
|
-
if let computed = self.computedUsedPercent {
|
|
62
|
-
return computed
|
|
63
|
-
}
|
|
64
|
-
return self.percentage
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
public var windowMinutes: Int? {
|
|
68
|
-
guard self.number > 0 else { return nil }
|
|
69
|
-
switch self.unit {
|
|
70
|
-
case .minutes:
|
|
71
|
-
return self.number
|
|
72
|
-
case .hours:
|
|
73
|
-
return self.number * 60
|
|
74
|
-
case .days:
|
|
75
|
-
return self.number * 24 * 60
|
|
76
|
-
case .unknown:
|
|
77
|
-
return nil
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
public var windowDescription: String? {
|
|
82
|
-
guard self.number > 0 else { return nil }
|
|
83
|
-
let unitLabel: String? = switch self.unit {
|
|
84
|
-
case .minutes: "minute"
|
|
85
|
-
case .hours: "hour"
|
|
86
|
-
case .days: "day"
|
|
87
|
-
case .unknown: nil
|
|
88
|
-
}
|
|
89
|
-
guard let unitLabel else { return nil }
|
|
90
|
-
let suffix = self.number == 1 ? unitLabel : "\(unitLabel)s"
|
|
91
|
-
return "\(self.number) \(suffix)"
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
public var windowLabel: String? {
|
|
95
|
-
guard let description = self.windowDescription else { return nil }
|
|
96
|
-
return "\(description) window"
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
private var computedUsedPercent: Double? {
|
|
100
|
-
guard self.usage > 0 else { return nil }
|
|
101
|
-
let limit = max(0, self.usage)
|
|
102
|
-
guard limit > 0 else { return nil }
|
|
103
|
-
|
|
104
|
-
let usedFromRemaining = limit - self.remaining
|
|
105
|
-
let used = max(0, min(limit, max(usedFromRemaining, self.currentValue)))
|
|
106
|
-
let percent = (Double(used) / Double(limit)) * 100
|
|
107
|
-
return min(100, max(0, percent))
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/// Usage detail for MCP tools
|
|
112
|
-
public struct ZaiUsageDetail: Sendable, Codable {
|
|
113
|
-
public let modelCode: String
|
|
114
|
-
public let usage: Int
|
|
115
|
-
|
|
116
|
-
public init(modelCode: String, usage: Int) {
|
|
117
|
-
self.modelCode = modelCode
|
|
118
|
-
self.usage = usage
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// MARK: - Model usage (24h breakdown)
|
|
123
|
-
|
|
124
|
-
/// Per-model usage entry from the model-usage endpoint.
|
|
125
|
-
public struct ZaiModelUsageEntry: Sendable {
|
|
126
|
-
public let modelCode: String
|
|
127
|
-
public let tokens: Int
|
|
128
|
-
public let prompts: Int
|
|
129
|
-
public let estimatedCostUSD: Double?
|
|
130
|
-
|
|
131
|
-
public init(modelCode: String, tokens: Int, prompts: Int, estimatedCostUSD: Double?) {
|
|
132
|
-
self.modelCode = modelCode
|
|
133
|
-
self.tokens = tokens
|
|
134
|
-
self.prompts = prompts
|
|
135
|
-
self.estimatedCostUSD = estimatedCostUSD
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/// Aggregated model usage from the 24h rolling window.
|
|
140
|
-
public struct ZaiModelUsageSummary: Sendable {
|
|
141
|
-
public let entries: [ZaiModelUsageEntry]
|
|
142
|
-
public let totalTokens: Int
|
|
143
|
-
public let totalPrompts: Int
|
|
144
|
-
public let totalEstimatedCostUSD: Double
|
|
145
|
-
public let windowStart: Date
|
|
146
|
-
public let windowEnd: Date
|
|
147
|
-
|
|
148
|
-
public init(
|
|
149
|
-
entries: [ZaiModelUsageEntry],
|
|
150
|
-
totalTokens: Int,
|
|
151
|
-
totalPrompts: Int,
|
|
152
|
-
totalEstimatedCostUSD: Double,
|
|
153
|
-
windowStart: Date,
|
|
154
|
-
windowEnd: Date)
|
|
155
|
-
{
|
|
156
|
-
self.entries = entries
|
|
157
|
-
self.totalTokens = totalTokens
|
|
158
|
-
self.totalPrompts = totalPrompts
|
|
159
|
-
self.totalEstimatedCostUSD = totalEstimatedCostUSD
|
|
160
|
-
self.windowStart = windowStart
|
|
161
|
-
self.windowEnd = windowEnd
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// MARK: - Tool usage (24h breakdown)
|
|
166
|
-
|
|
167
|
-
/// Per-tool MCP usage entry from the tool-usage endpoint.
|
|
168
|
-
public struct ZaiToolUsageEntry: Sendable {
|
|
169
|
-
public let toolName: String
|
|
170
|
-
public let count: Int
|
|
171
|
-
|
|
172
|
-
public init(toolName: String, count: Int) {
|
|
173
|
-
self.toolName = toolName
|
|
174
|
-
self.count = count
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/// Aggregated tool usage from the 24h rolling window.
|
|
179
|
-
public struct ZaiToolUsageSummary: Sendable {
|
|
180
|
-
public let entries: [ZaiToolUsageEntry]
|
|
181
|
-
public let totalCalls: Int
|
|
182
|
-
|
|
183
|
-
public init(entries: [ZaiToolUsageEntry], totalCalls: Int) {
|
|
184
|
-
self.entries = entries
|
|
185
|
-
self.totalCalls = totalCalls
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// MARK: - Pricing table
|
|
190
|
-
|
|
191
|
-
/// Static pricing lookup for z.ai models (USD per 1M tokens).
|
|
192
|
-
public enum ZaiModelPricing {
|
|
193
|
-
public struct Tier: Sendable {
|
|
194
|
-
public let inputPerMillion: Double
|
|
195
|
-
public let outputPerMillion: Double
|
|
196
|
-
public let contextWindow: Int
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
private static let tiers: [String: Tier] = [
|
|
200
|
-
"glm-4.7-flash": Tier(inputPerMillion: 0.06, outputPerMillion: 0.40, contextWindow: 203_000),
|
|
201
|
-
"glm-4.7-flash-thinking": Tier(inputPerMillion: 0.06, outputPerMillion: 0.40, contextWindow: 203_000),
|
|
202
|
-
"glm-4-32b": Tier(inputPerMillion: 0.10, outputPerMillion: 0.10, contextWindow: 128_000),
|
|
203
|
-
"glm-4.5-air": Tier(inputPerMillion: 0.13, outputPerMillion: 0.85, contextWindow: 131_000),
|
|
204
|
-
"glm-4.6v": Tier(inputPerMillion: 0.30, outputPerMillion: 0.90, contextWindow: 131_000),
|
|
205
|
-
"glm-4.6v-thinking": Tier(inputPerMillion: 0.30, outputPerMillion: 0.90, contextWindow: 131_000),
|
|
206
|
-
"glm-4.7": Tier(inputPerMillion: 0.38, outputPerMillion: 1.75, contextWindow: 203_000),
|
|
207
|
-
"glm-4.7-thinking": Tier(inputPerMillion: 0.38, outputPerMillion: 1.75, contextWindow: 203_000),
|
|
208
|
-
"glm-4.6": Tier(inputPerMillion: 0.39, outputPerMillion: 1.74, contextWindow: 205_000),
|
|
209
|
-
"glm-4.6-thinking": Tier(inputPerMillion: 0.39, outputPerMillion: 1.74, contextWindow: 205_000),
|
|
210
|
-
"glm-4.5v": Tier(inputPerMillion: 0.60, outputPerMillion: 1.80, contextWindow: 66000),
|
|
211
|
-
"glm-4.5v-thinking": Tier(inputPerMillion: 0.60, outputPerMillion: 1.80, contextWindow: 66000),
|
|
212
|
-
"glm-4.5": Tier(inputPerMillion: 0.60, outputPerMillion: 2.20, contextWindow: 131_000),
|
|
213
|
-
"glm-4.5-thinking": Tier(inputPerMillion: 0.60, outputPerMillion: 2.20, contextWindow: 131_000),
|
|
214
|
-
"glm-5": Tier(inputPerMillion: 0.72, outputPerMillion: 2.30, contextWindow: 203_000),
|
|
215
|
-
"glm-5-thinking": Tier(inputPerMillion: 0.72, outputPerMillion: 2.30, contextWindow: 203_000),
|
|
216
|
-
]
|
|
217
|
-
|
|
218
|
-
/// Returns pricing tier for a model code, case-insensitive with fuzzy matching.
|
|
219
|
-
public static func tier(for modelCode: String) -> Tier? {
|
|
220
|
-
let key = modelCode.lowercased().trimmingCharacters(in: .whitespacesAndNewlines)
|
|
221
|
-
if let exact = self.tiers[key] { return exact }
|
|
222
|
-
return self.tiers.first { key.contains($0.key) || $0.key.contains(key) }?.value
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/// Estimates cost assuming a 60/40 input/output token split (typical for coding).
|
|
226
|
-
public static func estimateCost(tokens: Int, modelCode: String) -> Double? {
|
|
227
|
-
guard let tier = self.tier(for: modelCode), tokens > 0 else { return nil }
|
|
228
|
-
let inputTokens = Double(tokens) * 0.6
|
|
229
|
-
let outputTokens = Double(tokens) * 0.4
|
|
230
|
-
let inputCost = (inputTokens / 1_000_000) * tier.inputPerMillion
|
|
231
|
-
let outputCost = (outputTokens / 1_000_000) * tier.outputPerMillion
|
|
232
|
-
return inputCost + outputCost
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// MARK: - Complete snapshot
|
|
237
|
-
|
|
238
|
-
/// Complete z.ai usage response including all 3 endpoints.
|
|
239
|
-
public struct ZaiUsageSnapshot: Sendable {
|
|
240
|
-
public let tokenLimit: ZaiLimitEntry?
|
|
241
|
-
public let timeLimit: ZaiLimitEntry?
|
|
242
|
-
public let planName: String?
|
|
243
|
-
public let modelUsage: ZaiModelUsageSummary?
|
|
244
|
-
public let toolUsage: ZaiToolUsageSummary?
|
|
245
|
-
public let updatedAt: Date
|
|
246
|
-
|
|
247
|
-
public init(
|
|
248
|
-
tokenLimit: ZaiLimitEntry?,
|
|
249
|
-
timeLimit: ZaiLimitEntry?,
|
|
250
|
-
planName: String?,
|
|
251
|
-
modelUsage: ZaiModelUsageSummary? = nil,
|
|
252
|
-
toolUsage: ZaiToolUsageSummary? = nil,
|
|
253
|
-
updatedAt: Date)
|
|
254
|
-
{
|
|
255
|
-
self.tokenLimit = tokenLimit
|
|
256
|
-
self.timeLimit = timeLimit
|
|
257
|
-
self.planName = planName
|
|
258
|
-
self.modelUsage = modelUsage
|
|
259
|
-
self.toolUsage = toolUsage
|
|
260
|
-
self.updatedAt = updatedAt
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
public var isValid: Bool {
|
|
264
|
-
self.tokenLimit != nil || self.timeLimit != nil
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
extension ZaiUsageSnapshot {
|
|
269
|
-
public func toUsageSnapshot() -> UsageSnapshot {
|
|
270
|
-
let primaryLimit = self.tokenLimit ?? self.timeLimit
|
|
271
|
-
let secondaryLimit = (self.tokenLimit != nil && self.timeLimit != nil) ? self.timeLimit : nil
|
|
272
|
-
|
|
273
|
-
let primary = primaryLimit.map { Self.rateWindow(for: $0) } ?? RateWindow(
|
|
274
|
-
usedPercent: 0,
|
|
275
|
-
windowMinutes: nil,
|
|
276
|
-
resetsAt: nil,
|
|
277
|
-
resetDescription: nil)
|
|
278
|
-
let secondary = secondaryLimit.map { Self.rateWindow(for: $0) }
|
|
279
|
-
|
|
280
|
-
let planName = self.planName?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
281
|
-
let loginMethod = (planName?.isEmpty ?? true) ? nil : planName
|
|
282
|
-
let identity = ProviderIdentitySnapshot(
|
|
283
|
-
providerID: .zai,
|
|
284
|
-
accountEmail: nil,
|
|
285
|
-
accountOrganization: nil,
|
|
286
|
-
loginMethod: loginMethod)
|
|
287
|
-
return UsageSnapshot(
|
|
288
|
-
primary: primary,
|
|
289
|
-
secondary: secondary,
|
|
290
|
-
tertiary: nil,
|
|
291
|
-
providerCost: nil,
|
|
292
|
-
zaiUsage: self,
|
|
293
|
-
updatedAt: self.updatedAt,
|
|
294
|
-
identity: identity)
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
private static func rateWindow(for limit: ZaiLimitEntry) -> RateWindow {
|
|
298
|
-
RateWindow(
|
|
299
|
-
usedPercent: limit.usedPercent,
|
|
300
|
-
windowMinutes: limit.type == .tokensLimit ? limit.windowMinutes : nil,
|
|
301
|
-
resetsAt: limit.nextResetTime,
|
|
302
|
-
resetDescription: self.resetDescription(for: limit))
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
private static func resetDescription(for limit: ZaiLimitEntry) -> String? {
|
|
306
|
-
if let label = limit.windowLabel {
|
|
307
|
-
return label
|
|
308
|
-
}
|
|
309
|
-
if limit.type == .timeLimit {
|
|
310
|
-
return "Monthly"
|
|
311
|
-
}
|
|
312
|
-
return nil
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// MARK: - Private API response models
|
|
317
|
-
|
|
318
|
-
private struct ZaiQuotaLimitResponse: Decodable {
|
|
319
|
-
let code: Int?
|
|
320
|
-
let msg: String?
|
|
321
|
-
let data: ZaiQuotaLimitData?
|
|
322
|
-
let success: Bool?
|
|
323
|
-
|
|
324
|
-
var isSuccess: Bool {
|
|
325
|
-
(self.success ?? (self.code == 200)) && (self.code ?? 200) == 200
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
var errorMessage: String {
|
|
329
|
-
self.msg ?? self.message ?? "Unknown API error (code: \(self.code ?? -1))"
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/// Some responses use "message" instead of "msg".
|
|
333
|
-
private let message: String?
|
|
334
|
-
|
|
335
|
-
private enum CodingKeys: String, CodingKey {
|
|
336
|
-
case code, msg, data, success, message
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
private struct ZaiQuotaLimitData: Decodable {
|
|
341
|
-
let limits: [ZaiLimitRaw]
|
|
342
|
-
let planName: String?
|
|
343
|
-
|
|
344
|
-
init(from decoder: Decoder) throws {
|
|
345
|
-
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
346
|
-
self.limits = try container.decode([ZaiLimitRaw].self, forKey: .limits)
|
|
347
|
-
let rawPlan = try [
|
|
348
|
-
container.decodeIfPresent(String.self, forKey: .planName),
|
|
349
|
-
container.decodeIfPresent(String.self, forKey: .plan),
|
|
350
|
-
container.decodeIfPresent(String.self, forKey: .planType),
|
|
351
|
-
container.decodeIfPresent(String.self, forKey: .packageName),
|
|
352
|
-
container.decodeIfPresent(String.self, forKey: .level),
|
|
353
|
-
].compactMap(\.self).first
|
|
354
|
-
let trimmed = rawPlan?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
355
|
-
self.planName = (trimmed?.isEmpty ?? true) ? nil : trimmed
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
private enum CodingKeys: String, CodingKey {
|
|
359
|
-
case limits
|
|
360
|
-
case planName
|
|
361
|
-
case plan
|
|
362
|
-
case planType = "plan_type"
|
|
363
|
-
case packageName
|
|
364
|
-
case level
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
private struct ZaiLimitRaw: Codable {
|
|
369
|
-
let type: String
|
|
370
|
-
let unit: Int?
|
|
371
|
-
let number: Int?
|
|
372
|
-
let usage: Int?
|
|
373
|
-
let currentValue: Int?
|
|
374
|
-
let remaining: Int?
|
|
375
|
-
let percentage: Int?
|
|
376
|
-
let usageDetails: [ZaiUsageDetail]?
|
|
377
|
-
let nextResetTime: Int?
|
|
378
|
-
|
|
379
|
-
func toLimitEntry() -> ZaiLimitEntry? {
|
|
380
|
-
guard let limitType = ZaiLimitType(rawValue: type) else { return nil }
|
|
381
|
-
let limitUnit = ZaiLimitUnit(rawValue: unit ?? 0) ?? .unknown
|
|
382
|
-
let resolvedUsage = self.usage ?? 0
|
|
383
|
-
let resolvedCurrent = self.currentValue ?? 0
|
|
384
|
-
let resolvedRemaining = self.remaining ?? max(0, resolvedUsage - resolvedCurrent)
|
|
385
|
-
let nextReset = self.nextResetTime.map { Date(timeIntervalSince1970: TimeInterval($0) / 1000) }
|
|
386
|
-
return ZaiLimitEntry(
|
|
387
|
-
type: limitType,
|
|
388
|
-
unit: limitUnit,
|
|
389
|
-
number: self.number ?? 0,
|
|
390
|
-
usage: resolvedUsage,
|
|
391
|
-
currentValue: resolvedCurrent,
|
|
392
|
-
remaining: resolvedRemaining,
|
|
393
|
-
percentage: Double(self.percentage ?? 0),
|
|
394
|
-
usageDetails: self.usageDetails ?? [],
|
|
395
|
-
nextResetTime: nextReset)
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/// Flexible model-usage API response (best-effort decoding).
|
|
400
|
-
private struct ZaiModelUsageResponse: Decodable {
|
|
401
|
-
let code: Int?
|
|
402
|
-
let success: Bool?
|
|
403
|
-
let data: ZaiModelUsageData?
|
|
404
|
-
|
|
405
|
-
struct ZaiModelUsageData: Decodable {
|
|
406
|
-
let models: [ZaiModelUsageRaw]?
|
|
407
|
-
let totalTokens: Int?
|
|
408
|
-
let totalPrompts: Int?
|
|
409
|
-
let total_tokens: Int?
|
|
410
|
-
let total_prompts: Int?
|
|
411
|
-
|
|
412
|
-
var resolvedTotalTokens: Int? {
|
|
413
|
-
self.totalTokens ?? self.total_tokens
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
var resolvedTotalPrompts: Int? {
|
|
417
|
-
self.totalPrompts ?? self.total_prompts
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
struct ZaiModelUsageRaw: Decodable {
|
|
422
|
-
let modelCode: String?
|
|
423
|
-
let model_code: String?
|
|
424
|
-
let model: String?
|
|
425
|
-
let tokens: Int?
|
|
426
|
-
let usage: Int?
|
|
427
|
-
let prompts: Int?
|
|
428
|
-
let calls: Int?
|
|
429
|
-
|
|
430
|
-
var resolvedModelCode: String? {
|
|
431
|
-
self.modelCode ?? self.model_code ?? self.model
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
var resolvedTokens: Int {
|
|
435
|
-
self.tokens ?? self.usage ?? 0
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
var resolvedPrompts: Int {
|
|
439
|
-
self.prompts ?? self.calls ?? 0
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
/// Flexible tool-usage API response (best-effort decoding).
|
|
445
|
-
private struct ZaiToolUsageResponse: Decodable {
|
|
446
|
-
let code: Int?
|
|
447
|
-
let success: Bool?
|
|
448
|
-
let data: ZaiToolUsageData?
|
|
449
|
-
|
|
450
|
-
struct ZaiToolUsageData: Decodable {
|
|
451
|
-
let tools: [ZaiToolUsageRaw]?
|
|
452
|
-
|
|
453
|
-
init(from decoder: Decoder) throws {
|
|
454
|
-
let container = try decoder.container(keyedBy: DynamicKey.self)
|
|
455
|
-
var toolEntries: [ZaiToolUsageRaw] = []
|
|
456
|
-
if let tools = try? container.decodeIfPresent(
|
|
457
|
-
[ZaiToolUsageRaw].self,
|
|
458
|
-
forKey: DynamicKey(stringValue: "tools")!)
|
|
459
|
-
{
|
|
460
|
-
toolEntries = tools
|
|
461
|
-
} else {
|
|
462
|
-
// Fallback: try top-level keys as tool names with int values
|
|
463
|
-
for key in container.allKeys {
|
|
464
|
-
if let count = try? container.decode(Int.self, forKey: key) {
|
|
465
|
-
toolEntries.append(ZaiToolUsageRaw(tool: key.stringValue, name: nil, count: count, usage: nil))
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
self.tools = toolEntries.isEmpty ? nil : toolEntries
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
struct ZaiToolUsageRaw: Decodable {
|
|
474
|
-
let tool: String?
|
|
475
|
-
let name: String?
|
|
476
|
-
let count: Int?
|
|
477
|
-
let usage: Int?
|
|
478
|
-
|
|
479
|
-
var resolvedName: String? {
|
|
480
|
-
self.tool ?? self.name
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
var resolvedCount: Int {
|
|
484
|
-
self.count ?? self.usage ?? 0
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
struct DynamicKey: CodingKey {
|
|
489
|
-
var stringValue: String
|
|
490
|
-
var intValue: Int?
|
|
491
|
-
init?(stringValue: String) {
|
|
492
|
-
self.stringValue = stringValue
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
init?(intValue: Int) {
|
|
496
|
-
self.stringValue = "\(intValue)"; self.intValue = intValue
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
// MARK: - Fetcher
|
|
502
|
-
|
|
503
|
-
/// Fetches usage stats from the z.ai API (all 3 endpoints).
|
|
504
|
-
public struct ZaiUsageFetcher: Sendable {
|
|
505
|
-
private static let log = RunicLog.logger("zai-usage")
|
|
506
|
-
|
|
507
|
-
private static let baseURL = "https://api.z.ai/api/monitor/usage"
|
|
508
|
-
private static let quotaAPIURL = "\(baseURL)/quota/limit"
|
|
509
|
-
private static let modelUsageAPIURL = "\(baseURL)/model-usage"
|
|
510
|
-
private static let toolUsageAPIURL = "\(baseURL)/tool-usage"
|
|
511
|
-
|
|
512
|
-
/// Fetches all available usage data from z.ai in parallel.
|
|
513
|
-
public static func fetchUsage(apiKey: String) async throws -> ZaiUsageSnapshot {
|
|
514
|
-
guard !apiKey.isEmpty else {
|
|
515
|
-
throw ZaiUsageError.invalidCredentials
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
// Fetch quota (required) and model/tool usage (best-effort) concurrently.
|
|
519
|
-
async let quotaTask = self.fetchQuota(apiKey: apiKey)
|
|
520
|
-
async let modelTask = self.fetchModelUsageBestEffort(apiKey: apiKey)
|
|
521
|
-
async let toolTask = self.fetchToolUsageBestEffort(apiKey: apiKey)
|
|
522
|
-
|
|
523
|
-
let (tokenLimit, timeLimit, planName) = try await quotaTask
|
|
524
|
-
let modelUsage = await modelTask
|
|
525
|
-
let toolUsage = await toolTask
|
|
526
|
-
|
|
527
|
-
return ZaiUsageSnapshot(
|
|
528
|
-
tokenLimit: tokenLimit,
|
|
529
|
-
timeLimit: timeLimit,
|
|
530
|
-
planName: planName,
|
|
531
|
-
modelUsage: modelUsage,
|
|
532
|
-
toolUsage: toolUsage,
|
|
533
|
-
updatedAt: Date())
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
// MARK: - Quota endpoint (required)
|
|
537
|
-
|
|
538
|
-
private static func fetchQuota(apiKey: String) async throws -> (ZaiLimitEntry?, ZaiLimitEntry?, String?) {
|
|
539
|
-
let request = try self.makeRequest(url: self.quotaAPIURL, apiKey: apiKey)
|
|
540
|
-
let (data, response) = try await URLSession.shared.data(for: request)
|
|
541
|
-
|
|
542
|
-
guard let httpResponse = response as? HTTPURLResponse else {
|
|
543
|
-
throw ZaiUsageError.networkError("Invalid response")
|
|
544
|
-
}
|
|
545
|
-
guard httpResponse.statusCode == 200 else {
|
|
546
|
-
let errorMessage = String(data: data, encoding: .utf8) ?? "Unknown error"
|
|
547
|
-
Self.log.error("z.ai quota API returned \(httpResponse.statusCode): \(errorMessage)")
|
|
548
|
-
throw ZaiUsageError.apiError("HTTP \(httpResponse.statusCode): \(errorMessage)")
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
Self.log.debug("z.ai quota response: HTTP \(httpResponse.statusCode), \(data.count) bytes")
|
|
552
|
-
|
|
553
|
-
let apiResponse: ZaiQuotaLimitResponse
|
|
554
|
-
do {
|
|
555
|
-
apiResponse = try JSONDecoder().decode(ZaiQuotaLimitResponse.self, from: data)
|
|
556
|
-
} catch {
|
|
557
|
-
let body = String(data: data, encoding: .utf8) ?? "<binary>"
|
|
558
|
-
Self.log.error("z.ai quota parse failed: \(error) — body: \(body)")
|
|
559
|
-
throw ZaiUsageError.parseFailed(error.localizedDescription)
|
|
560
|
-
}
|
|
561
|
-
guard apiResponse.isSuccess else {
|
|
562
|
-
throw ZaiUsageError.apiError(apiResponse.errorMessage)
|
|
563
|
-
}
|
|
564
|
-
guard let quotaData = apiResponse.data else {
|
|
565
|
-
throw ZaiUsageError.apiError("API returned success but no data")
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
var tokenLimit: ZaiLimitEntry?
|
|
569
|
-
var timeLimit: ZaiLimitEntry?
|
|
570
|
-
for limit in quotaData.limits {
|
|
571
|
-
if let entry = limit.toLimitEntry() {
|
|
572
|
-
switch entry.type {
|
|
573
|
-
case .tokensLimit: tokenLimit = entry
|
|
574
|
-
case .timeLimit: timeLimit = entry
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
return (tokenLimit, timeLimit, quotaData.planName)
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
// MARK: - Model usage endpoint (best-effort)
|
|
582
|
-
|
|
583
|
-
private static func fetchModelUsageBestEffort(apiKey: String) async -> ZaiModelUsageSummary? {
|
|
584
|
-
do {
|
|
585
|
-
return try await self.fetchModelUsage(apiKey: apiKey)
|
|
586
|
-
} catch {
|
|
587
|
-
self.log.info("z.ai model-usage endpoint unavailable: \(error.localizedDescription)")
|
|
588
|
-
return nil
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
private static func fetchModelUsage(apiKey: String) async throws -> ZaiModelUsageSummary {
|
|
593
|
-
let (startTime, endTime) = self.rolling24hWindow()
|
|
594
|
-
let urlString = "\(modelUsageAPIURL)?startTime=\(startTime)&endTime=\(endTime)"
|
|
595
|
-
let request = try self.makeRequest(url: urlString, apiKey: apiKey)
|
|
596
|
-
let (data, response) = try await URLSession.shared.data(for: request)
|
|
597
|
-
|
|
598
|
-
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
|
|
599
|
-
throw ZaiUsageError.apiError("model-usage endpoint returned non-200")
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
Self.log.debug("z.ai model-usage response: HTTP \(httpResponse.statusCode), \(data.count) bytes")
|
|
603
|
-
|
|
604
|
-
let raw = try JSONDecoder().decode(ZaiModelUsageResponse.self, from: data)
|
|
605
|
-
let models = raw.data?.models ?? []
|
|
606
|
-
|
|
607
|
-
var entries: [ZaiModelUsageEntry] = []
|
|
608
|
-
var totalTokens = 0
|
|
609
|
-
var totalPrompts = 0
|
|
610
|
-
var totalCost = 0.0
|
|
611
|
-
|
|
612
|
-
for model in models {
|
|
613
|
-
guard let code = model.resolvedModelCode else { continue }
|
|
614
|
-
let tokens = model.resolvedTokens
|
|
615
|
-
let prompts = model.resolvedPrompts
|
|
616
|
-
let cost = ZaiModelPricing.estimateCost(tokens: tokens, modelCode: code)
|
|
617
|
-
entries.append(ZaiModelUsageEntry(
|
|
618
|
-
modelCode: code,
|
|
619
|
-
tokens: tokens,
|
|
620
|
-
prompts: prompts,
|
|
621
|
-
estimatedCostUSD: cost))
|
|
622
|
-
totalTokens += tokens
|
|
623
|
-
totalPrompts += prompts
|
|
624
|
-
totalCost += cost ?? 0
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
// If the API returned totals, prefer those.
|
|
628
|
-
let resolvedTotalTokens = raw.data?.resolvedTotalTokens ?? totalTokens
|
|
629
|
-
let resolvedTotalPrompts = raw.data?.resolvedTotalPrompts ?? totalPrompts
|
|
630
|
-
|
|
631
|
-
let (startDate, endDate) = self.rolling24hDates()
|
|
632
|
-
return ZaiModelUsageSummary(
|
|
633
|
-
entries: entries.sorted { $0.tokens > $1.tokens },
|
|
634
|
-
totalTokens: resolvedTotalTokens,
|
|
635
|
-
totalPrompts: resolvedTotalPrompts,
|
|
636
|
-
totalEstimatedCostUSD: totalCost,
|
|
637
|
-
windowStart: startDate,
|
|
638
|
-
windowEnd: endDate)
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
// MARK: - Tool usage endpoint (best-effort)
|
|
642
|
-
|
|
643
|
-
private static func fetchToolUsageBestEffort(apiKey: String) async -> ZaiToolUsageSummary? {
|
|
644
|
-
do {
|
|
645
|
-
return try await self.fetchToolUsage(apiKey: apiKey)
|
|
646
|
-
} catch {
|
|
647
|
-
self.log.info("z.ai tool-usage endpoint unavailable: \(error.localizedDescription)")
|
|
648
|
-
return nil
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
private static func fetchToolUsage(apiKey: String) async throws -> ZaiToolUsageSummary {
|
|
653
|
-
let (startTime, endTime) = self.rolling24hWindow()
|
|
654
|
-
let urlString = "\(toolUsageAPIURL)?startTime=\(startTime)&endTime=\(endTime)"
|
|
655
|
-
let request = try self.makeRequest(url: urlString, apiKey: apiKey)
|
|
656
|
-
let (data, response) = try await URLSession.shared.data(for: request)
|
|
657
|
-
|
|
658
|
-
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
|
|
659
|
-
throw ZaiUsageError.apiError("tool-usage endpoint returned non-200")
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
Self.log.debug("z.ai tool-usage response: HTTP \(httpResponse.statusCode), \(data.count) bytes")
|
|
663
|
-
|
|
664
|
-
let raw = try JSONDecoder().decode(ZaiToolUsageResponse.self, from: data)
|
|
665
|
-
let tools = raw.data?.tools ?? []
|
|
666
|
-
|
|
667
|
-
var entries: [ZaiToolUsageEntry] = []
|
|
668
|
-
var total = 0
|
|
669
|
-
for tool in tools {
|
|
670
|
-
guard let name = tool.resolvedName else { continue }
|
|
671
|
-
let count = tool.resolvedCount
|
|
672
|
-
entries.append(ZaiToolUsageEntry(toolName: name, count: count))
|
|
673
|
-
total += count
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
return ZaiToolUsageSummary(
|
|
677
|
-
entries: entries.sorted { $0.count > $1.count },
|
|
678
|
-
totalCalls: total)
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
// MARK: - Helpers
|
|
682
|
-
|
|
683
|
-
private static func makeRequest(url: String, apiKey: String) throws -> URLRequest {
|
|
684
|
-
guard let requestURL = URL(string: url) else {
|
|
685
|
-
throw ZaiUsageError.networkError("Invalid URL: \(url)")
|
|
686
|
-
}
|
|
687
|
-
var request = URLRequest(url: requestURL)
|
|
688
|
-
request.httpMethod = "GET"
|
|
689
|
-
// z.ai expects "Bearer <token>" — add prefix if the user didn't include it.
|
|
690
|
-
let authValue = if apiKey.lowercased().hasPrefix("bearer ") {
|
|
691
|
-
"Bearer \(apiKey.dropFirst(7).trimmingCharacters(in: .whitespaces))"
|
|
692
|
-
} else {
|
|
693
|
-
"Bearer \(apiKey)"
|
|
694
|
-
}
|
|
695
|
-
request.setValue(authValue, forHTTPHeaderField: "Authorization")
|
|
696
|
-
request.setValue("application/json", forHTTPHeaderField: "Accept")
|
|
697
|
-
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
698
|
-
request.setValue("en-US,en", forHTTPHeaderField: "Accept-Language")
|
|
699
|
-
request.timeoutInterval = 15
|
|
700
|
-
return request
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
/// Returns (startTime, endTime) as millisecond timestamps for a 24h rolling window.
|
|
704
|
-
private static func rolling24hWindow() -> (Int64, Int64) {
|
|
705
|
-
let now = Date()
|
|
706
|
-
let calendar = Calendar.current
|
|
707
|
-
let startOfCurrentHour = calendar.dateInterval(of: .hour, for: now)!.start
|
|
708
|
-
let yesterday = calendar.date(byAdding: .day, value: -1, to: startOfCurrentHour)!
|
|
709
|
-
let endOfCurrentHour = calendar.date(byAdding: .second, value: 3599, to: startOfCurrentHour)!
|
|
710
|
-
|
|
711
|
-
let startMs = Int64(yesterday.timeIntervalSince1970 * 1000)
|
|
712
|
-
let endMs = Int64(endOfCurrentHour.timeIntervalSince1970 * 1000)
|
|
713
|
-
return (startMs, endMs)
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
private static func rolling24hDates() -> (Date, Date) {
|
|
717
|
-
let now = Date()
|
|
718
|
-
let calendar = Calendar.current
|
|
719
|
-
let startOfCurrentHour = calendar.dateInterval(of: .hour, for: now)!.start
|
|
720
|
-
let yesterday = calendar.date(byAdding: .day, value: -1, to: startOfCurrentHour)!
|
|
721
|
-
return (yesterday, now)
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
// MARK: - Errors
|
|
726
|
-
|
|
727
|
-
public enum ZaiUsageError: LocalizedError, Sendable {
|
|
728
|
-
case invalidCredentials
|
|
729
|
-
case networkError(String)
|
|
730
|
-
case apiError(String)
|
|
731
|
-
case parseFailed(String)
|
|
732
|
-
|
|
733
|
-
public var errorDescription: String? {
|
|
734
|
-
switch self {
|
|
735
|
-
case .invalidCredentials:
|
|
736
|
-
"Invalid z.ai API credentials"
|
|
737
|
-
case let .networkError(message):
|
|
738
|
-
"z.ai network error: \(message)"
|
|
739
|
-
case let .apiError(message):
|
|
740
|
-
"z.ai API error: \(message)"
|
|
741
|
-
case let .parseFailed(message):
|
|
742
|
-
"Failed to parse z.ai response: \(message)"
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
}
|