@sriinnu/runic 1.2.0 → 2.0.0
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 +11 -0
- package/README.md +8 -1
- package/RuniciOS/Core/RunicTypographyiOS.swift +24 -0
- package/RuniciOS/Views/ProviderDetailView.swift +9 -9
- package/RuniciOS/Views/ProviderListView.swift +10 -10
- package/RuniciOS/Widgets/LargeWidget.swift +14 -14
- package/RuniciOS/Widgets/LiveActivity.swift +19 -19
- package/RuniciOS/Widgets/LockScreenWidget.swift +15 -15
- package/RuniciOS/Widgets/MediumWidget.swift +10 -10
- package/RuniciOS/Widgets/RunicWidget.swift +5 -5
- package/RuniciOS/Widgets/SmallWidget.swift +9 -9
- package/Sources/Runic/About.swift +3 -3
- package/Sources/Runic/AppNotifications.swift +5 -3
- package/Sources/Runic/Controllers/StatusItemController+Actions.swift +7 -3
- package/Sources/Runic/Controllers/StatusItemController+Animation.swift +5 -4
- package/Sources/Runic/Controllers/StatusItemController+ChartSubmenus.swift +30 -16
- package/Sources/Runic/Controllers/StatusItemController+CustomProviders.swift +6 -3
- package/Sources/Runic/Controllers/StatusItemController+Menu.swift +18 -13
- package/Sources/Runic/Controllers/StatusItemController+MenuCards.swift +6 -4
- package/Sources/Runic/Controllers/StatusItemController+MenuHelpers.swift +40 -12
- package/Sources/Runic/Controllers/StatusItemController.swift +43 -43
- package/Sources/Runic/Core/BudgetNotificationManager.swift +2 -1
- package/Sources/Runic/Core/Login/ClaudeLoginRunner.swift +2 -2
- package/Sources/Runic/Core/Login/CodexLoginRunner.swift +1 -1
- package/Sources/Runic/Core/Login/CursorLoginRunner.swift +4 -4
- package/Sources/Runic/Core/Login/GeminiLoginRunner.swift +1 -1
- package/Sources/Runic/Core/Rendering/IconRenderer.swift +91 -85
- package/Sources/Runic/Core/Rendering/IconView.swift +3 -1
- package/Sources/Runic/Core/RunicColors.swift +6 -6
- package/Sources/Runic/Core/RunicSpacing.swift +7 -7
- package/Sources/Runic/Core/RunicTypography.swift +206 -0
- package/Sources/Runic/Core/Stores/AuggieTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/AzureOpenAITokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/CerebrasTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/CohereTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/CopilotTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/CustomProviderStore.swift +10 -10
- package/Sources/Runic/Core/Stores/DeepSeekTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/FireworksTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/GroqTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/KimiTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/MiniMaxCookieHeaderStore.swift +1 -3
- package/Sources/Runic/Core/Stores/MiniMaxGroupIDStore.swift +1 -3
- package/Sources/Runic/Core/Stores/MiniMaxTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/MistralTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/OpenRouterTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/PerplexityTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/ProviderToggleStore.swift +1 -1
- package/Sources/Runic/Core/Stores/QwenTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/SambaNovaTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/SettingsStore.swift +89 -51
- package/Sources/Runic/Core/Stores/TogetherTokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/UsageStore+Accessors.swift +19 -6
- package/Sources/Runic/Core/Stores/UsageStore+TokenCost.swift +1 -1
- package/Sources/Runic/Core/Stores/UsageStore+WidgetSnapshot.swift +1 -1
- package/Sources/Runic/Core/Stores/UsageStore.swift +187 -161
- package/Sources/Runic/Core/Stores/XAITokenStore.swift +1 -3
- package/Sources/Runic/Core/Stores/ZaiTokenStore.swift +1 -2
- package/Sources/Runic/Core/UsageExporter.swift +8 -4
- package/Sources/Runic/ProviderRegistry.swift +1 -1
- package/Sources/Runic/Providers/Antigravity/AntigravityProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Auggie/AuggieProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Azure/AzureProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Bedrock/BedrockProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Cerebras/CerebrasProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Codex/CodexProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Cohere/CohereProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Cursor/CursorProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/DeepSeek/DeepSeekProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Factory/FactoryProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Fireworks/FireworksProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Gemini/GeminiProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Groq/GroqProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Kimi/KimiProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/MiniMax/MiniMaxProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Mistral/MistralProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/OpenRouter/OpenRouterProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Perplexity/PerplexityProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/SambaNova/SambaNovaProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Shared/ProviderImplementation.swift +5 -2
- package/Sources/Runic/Providers/Shared/ProviderImplementationRegistry.swift +1 -1
- package/Sources/Runic/Providers/Shared/ProviderSettingsDescriptors.swift +1 -1
- package/Sources/Runic/Providers/Together/TogetherProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/XAI/XAIProviderImplementation.swift +1 -1
- package/Sources/Runic/Providers/Zai/ZaiProviderImplementation.swift +1 -1
- 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/RunicApp.swift +46 -36
- package/Sources/Runic/SessionQuotaNotifications.swift +2 -2
- package/Sources/Runic/UsagePaceText.swift +1 -1
- package/Sources/Runic/UsageProgressBar.swift +13 -9
- package/Sources/Runic/Utilities/LoadingPattern.swift +4 -2
- package/Sources/Runic/Utilities/PerformanceConstants.swift +28 -28
- package/Sources/Runic/Views/Menu/AlertsMenuView.swift +19 -21
- package/Sources/Runic/Views/Menu/CostComparativeChartMenuView.swift +19 -19
- package/Sources/Runic/Views/Menu/CostHistoryChartMenuView.swift +7 -7
- package/Sources/Runic/Views/Menu/CreditsHistoryChartMenuView.swift +5 -5
- package/Sources/Runic/Views/Menu/EfficiencyMetricsMenuView.swift +29 -30
- package/Sources/Runic/Views/Menu/HeroStatCardsMenuView.swift +20 -17
- package/Sources/Runic/Views/Menu/HourlyActivityChartMenuView.swift +14 -14
- package/Sources/Runic/Views/Menu/InlineUsageChartView.swift +12 -10
- package/Sources/Runic/Views/Menu/MenuCardEntranceModifier.swift +3 -4
- package/Sources/Runic/Views/Menu/MenuCardSidebarView.swift +5 -25
- package/Sources/Runic/Views/Menu/MenuCardSkeletonView.swift +1 -1
- package/Sources/Runic/Views/Menu/MenuCardView.swift +120 -131
- package/Sources/Runic/Views/Menu/MenuContent.swift +11 -8
- package/Sources/Runic/Views/Menu/MenuDescriptor.swift +4 -2
- package/Sources/Runic/Views/Menu/MenuHighlightStyle.swift +1 -8
- package/Sources/Runic/Views/Menu/ModelBreakdownMenuView.swift +20 -14
- package/Sources/Runic/Views/Menu/OverviewMenuView.swift +18 -15
- package/Sources/Runic/Views/Menu/ProjectBreakdownMenuView.swift +16 -11
- package/Sources/Runic/Views/Menu/ProjectBudgetMenuView.swift +27 -27
- package/Sources/Runic/Views/Menu/ProviderTabBarView.swift +4 -6
- package/Sources/Runic/Views/Menu/SubscriptionUtilizationChartMenuView.swift +24 -11
- package/Sources/Runic/Views/Menu/UsageBreakdownChartMenuView.swift +5 -5
- package/Sources/Runic/Views/Menu/UsageHeatmapMenuView.swift +7 -8
- package/Sources/Runic/Views/Menu/UsageTimelineChartMenuView.swift +22 -17
- package/Sources/Runic/Views/Menu/UsageWindowComparisonChartMenuView.swift +8 -7
- package/Sources/Runic/Views/Menu/WeeklyActivityChartMenuView.swift +7 -7
- package/Sources/Runic/Views/Performance/PerformanceDashboardView.swift +50 -47
- package/Sources/Runic/Views/Preferences/LiquidComponents.swift +15 -14
- package/Sources/Runic/Views/Preferences/PreferencesAboutPane.swift +7 -7
- package/Sources/Runic/Views/Preferences/PreferencesAdvancedPane.swift +27 -27
- package/Sources/Runic/Views/Preferences/PreferencesAlertsPane.swift +38 -42
- package/Sources/Runic/Views/Preferences/PreferencesAnalyticsPane.swift +39 -43
- package/Sources/Runic/Views/Preferences/PreferencesBudgetsPane.swift +21 -21
- package/Sources/Runic/Views/Preferences/PreferencesComponents.swift +7 -7
- package/Sources/Runic/Views/Preferences/PreferencesCustomProvidersPane.swift +49 -50
- package/Sources/Runic/Views/Preferences/PreferencesDebugPane.swift +10 -10
- package/Sources/Runic/Views/Preferences/PreferencesGeneralPane.swift +40 -21
- package/Sources/Runic/Views/Preferences/PreferencesHelpPane.swift +7 -7
- package/Sources/Runic/Views/Preferences/PreferencesIntegrationsPane.swift +44 -39
- package/Sources/Runic/Views/Preferences/PreferencesPerformancePane.swift +26 -23
- package/Sources/Runic/Views/Preferences/PreferencesProvidersPane.swift +271 -226
- package/Sources/Runic/Views/Preferences/PreferencesSelection.swift +6 -2
- package/Sources/Runic/Views/Preferences/PreferencesSyncPane.swift +7 -5
- package/Sources/Runic/Views/Preferences/PreferencesView.swift +38 -31
- package/Sources/Runic/Views/Rating/QualityRatingView.swift +11 -11
- package/Sources/Runic/Views/Team/TeamDashboardView.swift +29 -24
- package/Sources/Runic/Views/Team/TeamInviteSheet.swift +16 -16
- package/Sources/Runic/Views/Team/TeamManagementView.swift +50 -49
- package/Sources/Runic/Views/Team/TeamMemberRow.swift +8 -8
- package/Sources/RunicCLI/CLIEntry.swift +83 -42
- package/Sources/RunicCLI/CLIRenderer.swift +1 -1
- package/Sources/RunicCLI/Commands/EnhancedUsageCommand.swift +60 -60
- package/Sources/RunicCLI/Commands/ModelsCommand.swift +45 -44
- package/Sources/RunicCLI/Commands/ProjectsCommand.swift +83 -69
- package/Sources/RunicCLI/Commands/ResetCommand.swift +50 -49
- package/Sources/RunicCLI/Commands/UsageLedgerSourceFactory.swift +31 -32
- package/Sources/RunicClaudeWebProbe/main.swift +1 -1
- package/Sources/RunicCore/AlertRuleStore.swift +20 -20
- package/Sources/RunicCore/BrowserCookieImportOrder.swift +3 -3
- package/Sources/RunicCore/CostUsageModels.swift +1 -1
- package/Sources/RunicCore/CustomProviders/CustomProviderModels.swift +29 -30
- package/Sources/RunicCore/CustomProviders/GenericProviderFetcher.swift +73 -75
- package/Sources/RunicCore/CustomProviders/ProviderTemplates.swift +53 -109
- package/Sources/RunicCore/Host/PTY/TTYCommandRunner.swift +3 -3
- package/Sources/RunicCore/Integrations/GitHubIntegration.swift +3 -3
- package/Sources/RunicCore/Models/EnhancedUsageModels.swift +47 -48
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardBrowserCookieImporter.swift +1 -1
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardFetcher.swift +1 -1
- package/Sources/RunicCore/Performance/PerformanceModels.swift +4 -4
- package/Sources/RunicCore/Performance/PerformanceStorageImpl.swift +81 -64
- package/Sources/RunicCore/Policy/UsagePolicyEngine.swift +2 -2
- package/Sources/RunicCore/ProjectBudgetStore.swift +15 -12
- package/Sources/RunicCore/Providers/Antigravity/AntigravityProviderDescriptor.swift +4 -2
- package/Sources/RunicCore/Providers/Antigravity/AntigravityStatusProbe.swift +2 -2
- package/Sources/RunicCore/Providers/Auggie/AuggieProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/Auggie/AuggieUsageFetcher.swift +3 -3
- package/Sources/RunicCore/Providers/Azure/AzureProviderDescriptor.swift +8 -8
- package/Sources/RunicCore/Providers/Azure/AzureUsageFetcher.swift +3 -3
- package/Sources/RunicCore/Providers/Bedrock/BedrockProviderDescriptor.swift +6 -6
- package/Sources/RunicCore/Providers/Bedrock/BedrockUsageFetcher.swift +3 -7
- package/Sources/RunicCore/Providers/Cerebras/CerebrasProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/Cerebras/CerebrasUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthUsageFetcher.swift +3 -3
- package/Sources/RunicCore/Providers/Claude/ClaudeProviderDescriptor.swift +4 -2
- package/Sources/RunicCore/Providers/Claude/ClaudeStatusProbe.swift +4 -4
- package/Sources/RunicCore/Providers/Claude/ClaudeUsageDataSource.swift +3 -1
- package/Sources/RunicCore/Providers/Claude/ClaudeWeb/ClaudeWebAPIFetcher.swift +1 -1
- package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthUsageFetcher.swift +1 -1
- package/Sources/RunicCore/Providers/Codex/CodexProviderDescriptor.swift +4 -2
- package/Sources/RunicCore/Providers/Codex/CodexUsageDataSource.swift +3 -1
- package/Sources/RunicCore/Providers/Codex/CodexWebDashboardStrategy.swift +5 -3
- package/Sources/RunicCore/Providers/Cohere/CohereProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/Cohere/CohereUsageFetcher.swift +3 -3
- package/Sources/RunicCore/Providers/Copilot/CopilotGitHubCLITokenReader.swift +7 -4
- package/Sources/RunicCore/Providers/Copilot/CopilotProviderDescriptor.swift +4 -4
- package/Sources/RunicCore/Providers/Copilot/CopilotUsageFetcher.swift +5 -3
- package/Sources/RunicCore/Providers/Copilot/CopilotVSCodeTokenReader.swift +9 -10
- package/Sources/RunicCore/Providers/Cursor/CursorProviderDescriptor.swift +4 -2
- package/Sources/RunicCore/Providers/DeepSeek/DeepSeekProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/DeepSeek/DeepSeekUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/Factory/FactoryLocalStorageImporter.swift +4 -4
- package/Sources/RunicCore/Providers/Factory/FactoryProviderDescriptor.swift +4 -2
- package/Sources/RunicCore/Providers/Factory/FactoryStatusProbe.swift +2 -2
- package/Sources/RunicCore/Providers/Fireworks/FireworksProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/Fireworks/FireworksUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/Gemini/GeminiProviderDescriptor.swift +4 -2
- package/Sources/RunicCore/Providers/Gemini/GeminiStatusProbe.swift +5 -2
- package/Sources/RunicCore/Providers/Groq/GroqProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/Groq/GroqUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/Kimi/KimiProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/Kimi/KimiUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/MiniMax/MiniMaxProviderDescriptor.swift +10 -5
- package/Sources/RunicCore/Providers/MiniMax/MiniMaxUsageFetcher.swift +7 -7
- package/Sources/RunicCore/Providers/MiniMax/MiniMaxWebUsageFetcher.swift +10 -10
- package/Sources/RunicCore/Providers/Mistral/MistralProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/Mistral/MistralUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/OpenRouter/OpenRouterProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/OpenRouter/OpenRouterUsageFetcher.swift +23 -10
- package/Sources/RunicCore/Providers/Perplexity/PerplexityProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/Perplexity/PerplexityUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/ProviderFetchPlan.swift +2 -2
- package/Sources/RunicCore/Providers/ProviderTokenResolver.swift +2 -2
- package/Sources/RunicCore/Providers/Qwen/QwenProviderDescriptor.swift +5 -3
- package/Sources/RunicCore/Providers/Qwen/QwenUsageStats.swift +26 -13
- package/Sources/RunicCore/Providers/SambaNova/SambaNovaProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/SambaNova/SambaNovaUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/Together/TogetherProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/Together/TogetherUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/VertexAI/VertexAIProviderDescriptor.swift +5 -5
- package/Sources/RunicCore/Providers/VertexAI/VertexAISettingsReader.swift +1 -1
- package/Sources/RunicCore/Providers/VertexAI/VertexAIUsageFetcher.swift +3 -3
- package/Sources/RunicCore/Providers/XAI/XAIProviderDescriptor.swift +2 -2
- package/Sources/RunicCore/Providers/XAI/XAIUsageFetcher.swift +2 -2
- package/Sources/RunicCore/Providers/Zai/ZaiProviderDescriptor.swift +4 -2
- package/Sources/RunicCore/Providers/Zai/ZaiUsageStats.swift +48 -21
- package/Sources/RunicCore/Sync/BackgroundSyncManager.swift +76 -77
- package/Sources/RunicCore/Sync/SyncConflictResolver.swift +55 -58
- package/Sources/RunicCore/Sync/SyncProtocol.swift +21 -22
- package/Sources/RunicCore/Sync/SyncRecord.swift +46 -49
- package/Sources/RunicCore/Sync/SyncUsageExample.swift +44 -50
- package/Sources/RunicCore/Sync/TeamSyncRecords.swift +94 -101
- package/Sources/RunicCore/Sync/iCloudSyncEngine.swift +51 -46
- package/Sources/RunicCore/Team/TeamModels.swift +111 -110
- package/Sources/RunicCore/Team/TeamStore.swift +126 -109
- package/Sources/RunicCore/UsageFetcher.swift +2 -2
- package/Sources/RunicCore/UsageFormatter.swift +25 -25
- package/Sources/RunicCore/UsageLedger/ClaudeUsageLogSource.swift +27 -13
- package/Sources/RunicCore/UsageLedger/CodexUsageLogSource.swift +11 -3
- package/Sources/RunicCore/UsageLedger/LedgerCache.swift +5 -2
- package/Sources/RunicCore/UsageLedger/OTelGenAILedgerAdapter.swift +1 -1
- package/Sources/RunicCore/UsageLedger/UsageLedgerAggregator.swift +40 -25
- package/Sources/RunicCore/UsageLedger/UsageLedgerInsightsAdvisor.swift +1 -1
- package/Sources/RunicCore/UsageLedger/UsageLedgerProjectIdentity.swift +55 -16
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageCache.swift +6 -6
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageJsonl.swift +1 -1
- package/Sources/RunicCore/Vendored/CostUsage/CostUsagePricing.swift +2 -2
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner.swift +5 -5
- package/Tests/RunicTests/AppDelegateTests.swift +8 -3
- package/Tests/RunicTests/BrowserCookieOrderLabelTests.swift +2 -3
- package/Tests/RunicTests/CLIArgumentParsingTests.swift +3 -4
- package/Tests/RunicTests/CLICostTests.swift +6 -7
- package/Tests/RunicTests/CLIProviderSelectionTests.swift +2 -3
- package/Tests/RunicTests/CLISnapshotTests.swift +3 -4
- package/Tests/RunicTests/CLIWebFallbackTests.swift +3 -4
- package/Tests/RunicTests/ClaudeOAuthTests.swift +11 -12
- package/Tests/RunicTests/ClaudeResilienceTests.swift +3 -4
- package/Tests/RunicTests/ClaudeUsageTests.swift +20 -21
- package/Tests/RunicTests/CodexOAuthTests.swift +7 -8
- package/Tests/RunicTests/CodexUsageLogSourceTests.swift +1 -3
- package/Tests/RunicTests/CopilotTokenResolverTests.swift +5 -6
- package/Tests/RunicTests/CopilotVSCodeTokenReaderTests.swift +4 -5
- package/Tests/RunicTests/CostUsageDecodingTests.swift +15 -17
- package/Tests/RunicTests/CostUsagePricingTests.swift +5 -7
- package/Tests/RunicTests/CostUsageScannerTests.swift +10 -12
- package/Tests/RunicTests/CursorStatusProbeTests.swift +15 -16
- package/Tests/RunicTests/FactoryStatusProbeTests.swift +3 -5
- package/Tests/RunicTests/GeminiLoginAlertTests.swift +3 -4
- package/Tests/RunicTests/GeminiStatusProbeAPITests.swift +11 -11
- package/Tests/RunicTests/GeminiStatusProbePlanTests.swift +8 -8
- package/Tests/RunicTests/GeminiStatusProbeTests.swift +20 -21
- package/Tests/RunicTests/GoogleWorkspaceStatusTests.swift +2 -3
- package/Tests/RunicTests/InstallOriginTests.swift +1 -2
- package/Tests/RunicTests/KeyboardShortcutsBundleTests.swift +2 -2
- package/Tests/RunicTests/LiveAccountTests.swift +3 -3
- package/Tests/RunicTests/LoadingPatternTests.swift +3 -4
- package/Tests/RunicTests/MenuCardModelTests.swift +33 -34
- package/Tests/RunicTests/MiniMaxCookieHeaderStoreTestSupport.swift +4 -1
- package/Tests/RunicTests/MiniMaxGroupIDStoreTestSupport.swift +4 -1
- package/Tests/RunicTests/MiniMaxParsingTests.swift +4 -5
- package/Tests/RunicTests/MiniMaxTokenStoreTestSupport.swift +4 -1
- package/Tests/RunicTests/OTelGenAILedgerAdapterTests.swift +4 -6
- package/Tests/RunicTests/OpenAIDashboardBrowserCookieImporterTests.swift +1 -2
- package/Tests/RunicTests/OpenAIDashboardFetcherCreditsWaitTests.swift +5 -6
- package/Tests/RunicTests/OpenAIDashboardOffscreenHostTests.swift +2 -3
- package/Tests/RunicTests/OpenAIDashboardParserTests.swift +12 -13
- package/Tests/RunicTests/OpenAIWebAccountSwitchTests.swift +17 -6
- package/Tests/RunicTests/OpenRouterTokenStoreTestSupport.swift +52 -13
- package/Tests/RunicTests/PathBuilderTests.swift +14 -15
- package/Tests/RunicTests/ProviderFetchPipelineTests.swift +3 -4
- package/Tests/RunicTests/ProviderIconResourcesTests.swift +1 -2
- package/Tests/RunicTests/ProviderMetadataStatusLinkTests.swift +1 -2
- package/Tests/RunicTests/ProviderSettingsDescriptorTests.swift +53 -19
- package/Tests/RunicTests/ProviderToggleStoreTests.swift +10 -11
- package/Tests/RunicTests/RunicTests.swift +6 -7
- package/Tests/RunicTests/SessionQuotaNotificationLogicTests.swift +5 -6
- package/Tests/RunicTests/SettingsStoreTests.swift +149 -45
- package/Tests/RunicTests/StatusItemAnimationTests.swift +8 -3
- package/Tests/RunicTests/StatusMenuTests.swift +63 -22
- package/Tests/RunicTests/StatusProbeTests.swift +28 -29
- package/Tests/RunicTests/SubprocessRunnerTests.swift +1 -3
- package/Tests/RunicTests/SubscriptionDetectionTests.swift +8 -9
- package/Tests/RunicTests/TTYCommandRunnerTests.swift +8 -9
- package/Tests/RunicTests/TeamShowbackExporterTests.swift +2 -4
- package/Tests/RunicTests/TextParsingTests.swift +1 -2
- package/Tests/RunicTests/UsageFormatterTests.swift +15 -16
- package/Tests/RunicTests/UsageLedgerAnomalyDetectionTests.swift +12 -14
- package/Tests/RunicTests/UsageLedgerForecastTests.swift +4 -6
- package/Tests/RunicTests/UsageLedgerInsightsAdvisorTests.swift +7 -9
- package/Tests/RunicTests/UsageLedgerProjectNameTests.swift +6 -8
- package/Tests/RunicTests/UsagePaceTests.swift +5 -6
- package/Tests/RunicTests/UsagePaceTextTests.swift +8 -9
- package/Tests/RunicTests/UsagePolicyEngineTests.swift +3 -5
- package/Tests/RunicTests/WidgetSnapshotTests.swift +1 -3
- package/Tests/RunicTests/ZaiProviderTests.swift +3 -5
- package/Tests/RunicTests/ZaiTokenStoreTestSupport.swift +4 -1
- package/appcast.xml +36 -76
- package/package.json +1 -1
- package/runic.png +0 -0
- package/runic.svg +15 -0
- package/version.env +2 -2
|
@@ -2,10 +2,9 @@ import Foundation
|
|
|
2
2
|
import Testing
|
|
3
3
|
@testable import RunicCore
|
|
4
4
|
|
|
5
|
-
@Suite
|
|
6
5
|
struct CopilotVSCodeTokenReaderTests {
|
|
7
6
|
@Test
|
|
8
|
-
func
|
|
7
|
+
func `extracts token from session array payload`() {
|
|
9
8
|
let token = "ghu_abcdefghijklmnopqrstuvwxyz1234567890"
|
|
10
9
|
let json = """
|
|
11
10
|
[
|
|
@@ -26,7 +25,7 @@ struct CopilotVSCodeTokenReaderTests {
|
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
@Test
|
|
29
|
-
func
|
|
28
|
+
func `extracts token from nested object payload`() {
|
|
30
29
|
let token = "github_pat_abcdefghijklmnopqrstuvwxyz1234567890"
|
|
31
30
|
let json = """
|
|
32
31
|
{
|
|
@@ -45,7 +44,7 @@ struct CopilotVSCodeTokenReaderTests {
|
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
@Test
|
|
48
|
-
func
|
|
47
|
+
func `ignores short token values`() {
|
|
49
48
|
let json = """
|
|
50
49
|
{
|
|
51
50
|
"sessions": [
|
|
@@ -61,7 +60,7 @@ struct CopilotVSCodeTokenReaderTests {
|
|
|
61
60
|
}
|
|
62
61
|
|
|
63
62
|
@Test
|
|
64
|
-
func
|
|
63
|
+
func `normalizes node buffer secret wrapper`() {
|
|
65
64
|
let raw = Data("""
|
|
66
65
|
{
|
|
67
66
|
"type": "Buffer",
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import Testing
|
|
3
|
-
|
|
4
3
|
@testable import RunicCore
|
|
5
4
|
|
|
6
|
-
@Suite
|
|
7
5
|
struct CostUsageDecodingTests {
|
|
8
6
|
@Test
|
|
9
|
-
func
|
|
7
|
+
func `decodes daily report type format`() throws {
|
|
10
8
|
let json = """
|
|
11
9
|
{
|
|
12
10
|
"type": "daily",
|
|
@@ -45,7 +43,7 @@ struct CostUsageDecodingTests {
|
|
|
45
43
|
}
|
|
46
44
|
|
|
47
45
|
@Test
|
|
48
|
-
func
|
|
46
|
+
func `decodes daily report legacy format`() throws {
|
|
49
47
|
let json = """
|
|
50
48
|
{
|
|
51
49
|
"daily": [
|
|
@@ -81,7 +79,7 @@ struct CostUsageDecodingTests {
|
|
|
81
79
|
}
|
|
82
80
|
|
|
83
81
|
@Test
|
|
84
|
-
func
|
|
82
|
+
func `decodes legacy cache token keys`() throws {
|
|
85
83
|
let json = """
|
|
86
84
|
{
|
|
87
85
|
"type": "daily",
|
|
@@ -109,7 +107,7 @@ struct CostUsageDecodingTests {
|
|
|
109
107
|
}
|
|
110
108
|
|
|
111
109
|
@Test
|
|
112
|
-
func
|
|
110
|
+
func `decodes daily report legacy format with model map`() throws {
|
|
113
111
|
let json = """
|
|
114
112
|
{
|
|
115
113
|
"daily": [
|
|
@@ -143,7 +141,7 @@ struct CostUsageDecodingTests {
|
|
|
143
141
|
}
|
|
144
142
|
|
|
145
143
|
@Test
|
|
146
|
-
func
|
|
144
|
+
func `decodes daily report legacy format with model map sorted`() throws {
|
|
147
145
|
let json = """
|
|
148
146
|
{
|
|
149
147
|
"daily": [
|
|
@@ -166,7 +164,7 @@ struct CostUsageDecodingTests {
|
|
|
166
164
|
}
|
|
167
165
|
|
|
168
166
|
@Test
|
|
169
|
-
func
|
|
167
|
+
func `decodes daily report legacy format with empty model map as nil`() throws {
|
|
170
168
|
let json = """
|
|
171
169
|
{
|
|
172
170
|
"daily": [
|
|
@@ -185,7 +183,7 @@ struct CostUsageDecodingTests {
|
|
|
185
183
|
}
|
|
186
184
|
|
|
187
185
|
@Test
|
|
188
|
-
func
|
|
186
|
+
func `decodes daily report legacy format prefers models used list over models map`() throws {
|
|
189
187
|
let json = """
|
|
190
188
|
{
|
|
191
189
|
"daily": [
|
|
@@ -207,7 +205,7 @@ struct CostUsageDecodingTests {
|
|
|
207
205
|
}
|
|
208
206
|
|
|
209
207
|
@Test
|
|
210
|
-
func
|
|
208
|
+
func `decodes daily report legacy format with models list`() throws {
|
|
211
209
|
let json = """
|
|
212
210
|
{
|
|
213
211
|
"daily": [
|
|
@@ -226,7 +224,7 @@ struct CostUsageDecodingTests {
|
|
|
226
224
|
}
|
|
227
225
|
|
|
228
226
|
@Test
|
|
229
|
-
func
|
|
227
|
+
func `decodes daily report legacy format with invalid models field`() throws {
|
|
230
228
|
let json = """
|
|
231
229
|
{
|
|
232
230
|
"daily": [
|
|
@@ -245,7 +243,7 @@ struct CostUsageDecodingTests {
|
|
|
245
243
|
}
|
|
246
244
|
|
|
247
245
|
@Test
|
|
248
|
-
func
|
|
246
|
+
func `decodes monthly report legacy format`() throws {
|
|
249
247
|
let json = """
|
|
250
248
|
{
|
|
251
249
|
"monthly": [
|
|
@@ -270,7 +268,7 @@ struct CostUsageDecodingTests {
|
|
|
270
268
|
}
|
|
271
269
|
|
|
272
270
|
@Test
|
|
273
|
-
func
|
|
271
|
+
func `selects most recent session`() throws {
|
|
274
272
|
let json = """
|
|
275
273
|
{
|
|
276
274
|
"type": "session",
|
|
@@ -306,7 +304,7 @@ struct CostUsageDecodingTests {
|
|
|
306
304
|
}
|
|
307
305
|
|
|
308
306
|
@Test
|
|
309
|
-
func
|
|
307
|
+
func `token snapshot selects most recent day`() throws {
|
|
310
308
|
let json = """
|
|
311
309
|
{
|
|
312
310
|
"type": "daily",
|
|
@@ -339,7 +337,7 @@ struct CostUsageDecodingTests {
|
|
|
339
337
|
}
|
|
340
338
|
|
|
341
339
|
@Test
|
|
342
|
-
func
|
|
340
|
+
func `token snapshot uses summary total cost when available`() throws {
|
|
343
341
|
let json = """
|
|
344
342
|
{
|
|
345
343
|
"type": "daily",
|
|
@@ -359,7 +357,7 @@ struct CostUsageDecodingTests {
|
|
|
359
357
|
}
|
|
360
358
|
|
|
361
359
|
@Test
|
|
362
|
-
func
|
|
360
|
+
func `token snapshot falls back to summed entries when summary missing`() throws {
|
|
363
361
|
let json = """
|
|
364
362
|
{
|
|
365
363
|
"type": "daily",
|
|
@@ -376,7 +374,7 @@ struct CostUsageDecodingTests {
|
|
|
376
374
|
}
|
|
377
375
|
|
|
378
376
|
@Test
|
|
379
|
-
func
|
|
377
|
+
func `token snapshot returns nil total when no costs present`() throws {
|
|
380
378
|
let json = """
|
|
381
379
|
{
|
|
382
380
|
"type": "daily",
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import Testing
|
|
2
|
-
|
|
3
2
|
@testable import RunicCore
|
|
4
3
|
|
|
5
|
-
@Suite
|
|
6
4
|
struct CostUsagePricingTests {
|
|
7
5
|
@Test
|
|
8
|
-
func
|
|
6
|
+
func `normalizes codex model variants`() {
|
|
9
7
|
#expect(CostUsagePricing.normalizeCodexModel("openai/gpt-5-codex") == "gpt-5")
|
|
10
8
|
#expect(CostUsagePricing.normalizeCodexModel("gpt-5.2-codex") == "gpt-5.2")
|
|
11
9
|
#expect(CostUsagePricing.normalizeCodexModel("gpt-5.1-codex-max") == "gpt-5.1")
|
|
12
10
|
}
|
|
13
11
|
|
|
14
12
|
@Test
|
|
15
|
-
func
|
|
13
|
+
func `codex cost supports gpt51 codex max`() {
|
|
16
14
|
let cost = CostUsagePricing.codexCostUSD(
|
|
17
15
|
model: "gpt-5.1-codex-max",
|
|
18
16
|
inputTokens: 100,
|
|
@@ -22,12 +20,12 @@ struct CostUsagePricingTests {
|
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
@Test
|
|
25
|
-
func
|
|
23
|
+
func `normalizes claude opus41 dated variants`() {
|
|
26
24
|
#expect(CostUsagePricing.normalizeClaudeModel("claude-opus-4-1-20250805") == "claude-opus-4-1")
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
@Test
|
|
30
|
-
func
|
|
28
|
+
func `claude cost supports opus41 dated variant`() {
|
|
31
29
|
let cost = CostUsagePricing.claudeCostUSD(
|
|
32
30
|
model: "claude-opus-4-1-20250805",
|
|
33
31
|
inputTokens: 10,
|
|
@@ -38,7 +36,7 @@ struct CostUsagePricingTests {
|
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
@Test
|
|
41
|
-
func
|
|
39
|
+
func `claude cost returns nil for unknown models`() {
|
|
42
40
|
let cost = CostUsagePricing.claudeCostUSD(
|
|
43
41
|
model: "glm-4.6",
|
|
44
42
|
inputTokens: 100,
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import Testing
|
|
3
|
-
|
|
4
3
|
@testable import RunicCore
|
|
5
4
|
|
|
6
|
-
@Suite
|
|
7
5
|
struct CostUsageScannerTests {
|
|
8
6
|
@Test
|
|
9
|
-
func
|
|
7
|
+
func `codex daily report parses token counts and caches`() throws {
|
|
10
8
|
let env = try CostUsageTestEnvironment()
|
|
11
9
|
defer { env.cleanup() }
|
|
12
10
|
|
|
@@ -91,7 +89,7 @@ struct CostUsageScannerTests {
|
|
|
91
89
|
}
|
|
92
90
|
|
|
93
91
|
@Test
|
|
94
|
-
func
|
|
92
|
+
func `claude daily report parses usage and caches`() throws {
|
|
95
93
|
let env = try CostUsageTestEnvironment()
|
|
96
94
|
defer { env.cleanup() }
|
|
97
95
|
|
|
@@ -138,7 +136,7 @@ struct CostUsageScannerTests {
|
|
|
138
136
|
}
|
|
139
137
|
|
|
140
138
|
@Test
|
|
141
|
-
func
|
|
139
|
+
func `claude parses large lines with usage at tail`() throws {
|
|
142
140
|
let env = try CostUsageTestEnvironment()
|
|
143
141
|
defer { env.cleanup() }
|
|
144
142
|
|
|
@@ -183,7 +181,7 @@ struct CostUsageScannerTests {
|
|
|
183
181
|
}
|
|
184
182
|
|
|
185
183
|
@Test
|
|
186
|
-
func
|
|
184
|
+
func `claude daily report refreshes when file changes`() throws {
|
|
187
185
|
let env = try CostUsageTestEnvironment()
|
|
188
186
|
defer { env.cleanup() }
|
|
189
187
|
|
|
@@ -248,7 +246,7 @@ struct CostUsageScannerTests {
|
|
|
248
246
|
}
|
|
249
247
|
|
|
250
248
|
@Test
|
|
251
|
-
func
|
|
249
|
+
func `codex incremental parsing uses previous totals`() throws {
|
|
252
250
|
let env = try CostUsageTestEnvironment()
|
|
253
251
|
defer { env.cleanup() }
|
|
254
252
|
|
|
@@ -327,7 +325,7 @@ struct CostUsageScannerTests {
|
|
|
327
325
|
}
|
|
328
326
|
|
|
329
327
|
@Test
|
|
330
|
-
func
|
|
328
|
+
func `claude incremental parsing reads appended lines only`() throws {
|
|
331
329
|
let env = try CostUsageTestEnvironment()
|
|
332
330
|
defer { env.cleanup() }
|
|
333
331
|
|
|
@@ -387,7 +385,7 @@ struct CostUsageScannerTests {
|
|
|
387
385
|
}
|
|
388
386
|
|
|
389
387
|
@Test
|
|
390
|
-
func
|
|
388
|
+
func `day key from timestamp matches ISO parsing`() {
|
|
391
389
|
let timestamps = [
|
|
392
390
|
"2025-12-20T23:59:59Z",
|
|
393
391
|
"2025-12-20T23:59:59+02:00",
|
|
@@ -401,7 +399,7 @@ struct CostUsageScannerTests {
|
|
|
401
399
|
}
|
|
402
400
|
|
|
403
401
|
@Test
|
|
404
|
-
func
|
|
402
|
+
func `claude deduplicates streaming chunks`() throws {
|
|
405
403
|
let env = try CostUsageTestEnvironment()
|
|
406
404
|
defer { env.cleanup() }
|
|
407
405
|
|
|
@@ -489,7 +487,7 @@ struct CostUsageScannerTests {
|
|
|
489
487
|
}
|
|
490
488
|
|
|
491
489
|
@Test
|
|
492
|
-
func
|
|
490
|
+
func `claude counts entries without ids as separate`() throws {
|
|
493
491
|
let env = try CostUsageTestEnvironment()
|
|
494
492
|
defer { env.cleanup() }
|
|
495
493
|
|
|
@@ -553,7 +551,7 @@ struct CostUsageScannerTests {
|
|
|
553
551
|
}
|
|
554
552
|
|
|
555
553
|
@Test
|
|
556
|
-
func
|
|
554
|
+
func `claude counts different request ids separately`() throws {
|
|
557
555
|
let env = try CostUsageTestEnvironment()
|
|
558
556
|
defer { env.cleanup() }
|
|
559
557
|
|
|
@@ -2,12 +2,11 @@ import Foundation
|
|
|
2
2
|
import Testing
|
|
3
3
|
@testable import RunicCore
|
|
4
4
|
|
|
5
|
-
@Suite
|
|
6
5
|
struct CursorStatusProbeTests {
|
|
7
6
|
// MARK: - Usage Summary Parsing
|
|
8
7
|
|
|
9
8
|
@Test
|
|
10
|
-
func
|
|
9
|
+
func `parses basic usage summary`() throws {
|
|
11
10
|
let json = """
|
|
12
11
|
{
|
|
13
12
|
"billingCycleStart": "2025-01-01T00:00:00.000Z",
|
|
@@ -38,7 +37,7 @@ struct CursorStatusProbeTests {
|
|
|
38
37
|
}
|
|
39
38
|
}
|
|
40
39
|
"""
|
|
41
|
-
let data = json.data(using: .utf8)
|
|
40
|
+
let data = try #require(json.data(using: .utf8))
|
|
42
41
|
let summary = try JSONDecoder().decode(CursorUsageSummary.self, from: data)
|
|
43
42
|
|
|
44
43
|
#expect(summary.membershipType == "pro")
|
|
@@ -51,7 +50,7 @@ struct CursorStatusProbeTests {
|
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
@Test
|
|
54
|
-
func
|
|
53
|
+
func `parses minimal usage summary`() throws {
|
|
55
54
|
let json = """
|
|
56
55
|
{
|
|
57
56
|
"membershipType": "hobby",
|
|
@@ -63,7 +62,7 @@ struct CursorStatusProbeTests {
|
|
|
63
62
|
}
|
|
64
63
|
}
|
|
65
64
|
"""
|
|
66
|
-
let data = json.data(using: .utf8)
|
|
65
|
+
let data = try #require(json.data(using: .utf8))
|
|
67
66
|
let summary = try JSONDecoder().decode(CursorUsageSummary.self, from: data)
|
|
68
67
|
|
|
69
68
|
#expect(summary.membershipType == "hobby")
|
|
@@ -73,7 +72,7 @@ struct CursorStatusProbeTests {
|
|
|
73
72
|
}
|
|
74
73
|
|
|
75
74
|
@Test
|
|
76
|
-
func
|
|
75
|
+
func `parses enterprise usage summary`() throws {
|
|
77
76
|
let json = """
|
|
78
77
|
{
|
|
79
78
|
"membershipType": "enterprise",
|
|
@@ -88,7 +87,7 @@ struct CursorStatusProbeTests {
|
|
|
88
87
|
}
|
|
89
88
|
}
|
|
90
89
|
"""
|
|
91
|
-
let data = json.data(using: .utf8)
|
|
90
|
+
let data = try #require(json.data(using: .utf8))
|
|
92
91
|
let summary = try JSONDecoder().decode(CursorUsageSummary.self, from: data)
|
|
93
92
|
|
|
94
93
|
#expect(summary.membershipType == "enterprise")
|
|
@@ -99,7 +98,7 @@ struct CursorStatusProbeTests {
|
|
|
99
98
|
// MARK: - User Info Parsing
|
|
100
99
|
|
|
101
100
|
@Test
|
|
102
|
-
func
|
|
101
|
+
func `parses user info`() throws {
|
|
103
102
|
let json = """
|
|
104
103
|
{
|
|
105
104
|
"email": "user@example.com",
|
|
@@ -108,7 +107,7 @@ struct CursorStatusProbeTests {
|
|
|
108
107
|
"sub": "auth0|12345"
|
|
109
108
|
}
|
|
110
109
|
"""
|
|
111
|
-
let data = json.data(using: .utf8)
|
|
110
|
+
let data = try #require(json.data(using: .utf8))
|
|
112
111
|
let userInfo = try JSONDecoder().decode(CursorUserInfo.self, from: data)
|
|
113
112
|
|
|
114
113
|
#expect(userInfo.email == "user@example.com")
|
|
@@ -120,7 +119,7 @@ struct CursorStatusProbeTests {
|
|
|
120
119
|
// MARK: - Snapshot Conversion
|
|
121
120
|
|
|
122
121
|
@Test
|
|
123
|
-
func
|
|
122
|
+
func `prefers plan ratio over percent field`() {
|
|
124
123
|
let snapshot = CursorStatusProbe()
|
|
125
124
|
.parseUsageSummary(
|
|
126
125
|
CursorUsageSummary(
|
|
@@ -149,7 +148,7 @@ struct CursorStatusProbeTests {
|
|
|
149
148
|
}
|
|
150
149
|
|
|
151
150
|
@Test
|
|
152
|
-
func
|
|
151
|
+
func `uses percent field when limit missing`() {
|
|
153
152
|
let snapshot = CursorStatusProbe()
|
|
154
153
|
.parseUsageSummary(
|
|
155
154
|
CursorUsageSummary(
|
|
@@ -178,7 +177,7 @@ struct CursorStatusProbeTests {
|
|
|
178
177
|
}
|
|
179
178
|
|
|
180
179
|
@Test
|
|
181
|
-
func
|
|
180
|
+
func `converts snapshot to usage snapshot`() {
|
|
182
181
|
let snapshot = CursorStatusSnapshot(
|
|
183
182
|
planPercentUsed: 45.0,
|
|
184
183
|
planUsedUSD: 22.50,
|
|
@@ -206,7 +205,7 @@ struct CursorStatusProbeTests {
|
|
|
206
205
|
}
|
|
207
206
|
|
|
208
207
|
@Test
|
|
209
|
-
func
|
|
208
|
+
func `uses individual on demand when no team usage`() {
|
|
210
209
|
let snapshot = CursorStatusSnapshot(
|
|
211
210
|
planPercentUsed: 10.0,
|
|
212
211
|
planUsedUSD: 5.0,
|
|
@@ -229,7 +228,7 @@ struct CursorStatusProbeTests {
|
|
|
229
228
|
}
|
|
230
229
|
|
|
231
230
|
@Test
|
|
232
|
-
func
|
|
231
|
+
func `formats membership types`() {
|
|
233
232
|
let testCases: [(input: String, expected: String)] = [
|
|
234
233
|
("pro", "Cursor Pro"),
|
|
235
234
|
("hobby", "Cursor Hobby"),
|
|
@@ -259,7 +258,7 @@ struct CursorStatusProbeTests {
|
|
|
259
258
|
}
|
|
260
259
|
|
|
261
260
|
@Test
|
|
262
|
-
func
|
|
261
|
+
func `handles nil on demand limit`() {
|
|
263
262
|
let snapshot = CursorStatusSnapshot(
|
|
264
263
|
planPercentUsed: 50.0,
|
|
265
264
|
planUsedUSD: 25.0,
|
|
@@ -287,7 +286,7 @@ struct CursorStatusProbeTests {
|
|
|
287
286
|
// MARK: - Session Store Serialization
|
|
288
287
|
|
|
289
288
|
@Test
|
|
290
|
-
func
|
|
289
|
+
func `session store saves and loads cookies`() async {
|
|
291
290
|
let store = CursorSessionStore.shared
|
|
292
291
|
|
|
293
292
|
// Clear any existing cookies
|
|
@@ -2,10 +2,9 @@ import Foundation
|
|
|
2
2
|
import Testing
|
|
3
3
|
@testable import RunicCore
|
|
4
4
|
|
|
5
|
-
@Suite
|
|
6
5
|
struct FactoryStatusSnapshotTests {
|
|
7
6
|
@Test
|
|
8
|
-
func
|
|
7
|
+
func `maps usage snapshot windows and login method`() {
|
|
9
8
|
let periodEnd = Date(timeIntervalSince1970: 1_738_368_000) // Feb 1, 2025
|
|
10
9
|
let snapshot = FactoryStatusSnapshot(
|
|
11
10
|
standardUserTokens: 50,
|
|
@@ -33,7 +32,7 @@ struct FactoryStatusSnapshotTests {
|
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
@Test
|
|
36
|
-
func
|
|
35
|
+
func `treats large allowances as unlimited`() {
|
|
37
36
|
let snapshot = FactoryStatusSnapshot(
|
|
38
37
|
standardUserTokens: 50_000_000,
|
|
39
38
|
standardOrgTokens: 0,
|
|
@@ -56,10 +55,9 @@ struct FactoryStatusSnapshotTests {
|
|
|
56
55
|
}
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
@Suite
|
|
60
58
|
struct FactoryStatusProbeWorkOSTests {
|
|
61
59
|
@Test
|
|
62
|
-
func
|
|
60
|
+
func `detects missing refresh token payload`() {
|
|
63
61
|
let payload = Data("""
|
|
64
62
|
{"error":"invalid_request","error_description":"Missing refresh token."}
|
|
65
63
|
""".utf8)
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import Testing
|
|
2
2
|
@testable import Runic
|
|
3
3
|
|
|
4
|
-
@Suite
|
|
5
4
|
struct GeminiLoginAlertTests {
|
|
6
5
|
@Test
|
|
7
|
-
func
|
|
6
|
+
func `returns alert for missing binary`() {
|
|
8
7
|
let result = GeminiLoginRunner.Result(outcome: .missingBinary)
|
|
9
8
|
let info = StatusItemController.geminiLoginAlertInfo(for: result)
|
|
10
9
|
#expect(info?.title == "Gemini CLI not found")
|
|
@@ -12,7 +11,7 @@ struct GeminiLoginAlertTests {
|
|
|
12
11
|
}
|
|
13
12
|
|
|
14
13
|
@Test
|
|
15
|
-
func
|
|
14
|
+
func `returns alert for launch failure`() {
|
|
16
15
|
let result = GeminiLoginRunner.Result(outcome: .launchFailed("Boom"))
|
|
17
16
|
let info = StatusItemController.geminiLoginAlertInfo(for: result)
|
|
18
17
|
#expect(info?.title == "Could not open Terminal for Gemini")
|
|
@@ -20,7 +19,7 @@ struct GeminiLoginAlertTests {
|
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
@Test
|
|
23
|
-
func
|
|
22
|
+
func `returns nil on success`() {
|
|
24
23
|
let result = GeminiLoginRunner.Result(outcome: .success)
|
|
25
24
|
let info = StatusItemController.geminiLoginAlertInfo(for: result)
|
|
26
25
|
#expect(info == nil)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import RunicCore
|
|
2
1
|
import Foundation
|
|
2
|
+
import RunicCore
|
|
3
3
|
import Testing
|
|
4
4
|
|
|
5
|
-
@Suite(
|
|
5
|
+
@Suite(.serialized)
|
|
6
6
|
struct GeminiStatusProbeAPITests {
|
|
7
7
|
@Test
|
|
8
|
-
func
|
|
8
|
+
func `missing credentials throws not logged in`() async throws {
|
|
9
9
|
let env = try GeminiTestEnvironment()
|
|
10
10
|
defer { env.cleanup() }
|
|
11
11
|
|
|
@@ -16,7 +16,7 @@ struct GeminiStatusProbeAPITests {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
@Test
|
|
19
|
-
func
|
|
19
|
+
func `rejects api key auth type`() async throws {
|
|
20
20
|
let env = try GeminiTestEnvironment()
|
|
21
21
|
defer { env.cleanup() }
|
|
22
22
|
try env.writeSettings(authType: "api-key")
|
|
@@ -28,7 +28,7 @@ struct GeminiStatusProbeAPITests {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
@Test
|
|
31
|
-
func
|
|
31
|
+
func `rejects vertex auth type`() async throws {
|
|
32
32
|
let env = try GeminiTestEnvironment()
|
|
33
33
|
defer { env.cleanup() }
|
|
34
34
|
try env.writeSettings(authType: "vertex-ai")
|
|
@@ -40,7 +40,7 @@ struct GeminiStatusProbeAPITests {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
@Test
|
|
43
|
-
func
|
|
43
|
+
func `refreshes expired token and updates stored credentials`() async throws {
|
|
44
44
|
let env = try GeminiTestEnvironment()
|
|
45
45
|
defer { env.cleanup() }
|
|
46
46
|
try env.writeCredentials(
|
|
@@ -112,7 +112,7 @@ struct GeminiStatusProbeAPITests {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
@Test
|
|
115
|
-
func
|
|
115
|
+
func `fails refresh when O auth config missing`() async throws {
|
|
116
116
|
let env = try GeminiTestEnvironment()
|
|
117
117
|
defer { env.cleanup() }
|
|
118
118
|
try env.writeCredentials(
|
|
@@ -139,7 +139,7 @@ struct GeminiStatusProbeAPITests {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
@Test
|
|
142
|
-
func
|
|
142
|
+
func `reports api errors`() async throws {
|
|
143
143
|
let env = try GeminiTestEnvironment()
|
|
144
144
|
defer { env.cleanup() }
|
|
145
145
|
try env.writeCredentials(
|
|
@@ -175,7 +175,7 @@ struct GeminiStatusProbeAPITests {
|
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
@Test
|
|
178
|
-
func
|
|
178
|
+
func `reports not logged in when access token missing`() async throws {
|
|
179
179
|
let env = try GeminiTestEnvironment()
|
|
180
180
|
defer { env.cleanup() }
|
|
181
181
|
try env.writeCredentials(
|
|
@@ -191,7 +191,7 @@ struct GeminiStatusProbeAPITests {
|
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
@Test
|
|
194
|
-
func
|
|
194
|
+
func `reports not logged in on401`() async throws {
|
|
195
195
|
let env = try GeminiTestEnvironment()
|
|
196
196
|
defer { env.cleanup() }
|
|
197
197
|
try env.writeCredentials(
|
|
@@ -227,7 +227,7 @@ struct GeminiStatusProbeAPITests {
|
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
@Test
|
|
230
|
-
func
|
|
230
|
+
func `reports parse errors for invalid payload`() async throws {
|
|
231
231
|
let env = try GeminiTestEnvironment()
|
|
232
232
|
defer { env.cleanup() }
|
|
233
233
|
try env.writeCredentials(
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import RunicCore
|
|
2
1
|
import Foundation
|
|
2
|
+
import RunicCore
|
|
3
3
|
import Testing
|
|
4
4
|
|
|
5
|
-
@Suite(
|
|
5
|
+
@Suite(.serialized)
|
|
6
6
|
struct GeminiStatusProbePlanTests {
|
|
7
7
|
@Test
|
|
8
|
-
func
|
|
8
|
+
func `selects project id for quota requests`() async throws {
|
|
9
9
|
let env = try GeminiTestEnvironment()
|
|
10
10
|
defer { env.cleanup() }
|
|
11
11
|
try env.writeCredentials(
|
|
@@ -56,7 +56,7 @@ struct GeminiStatusProbePlanTests {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
@Test
|
|
59
|
-
func
|
|
59
|
+
func `detects paid from standard tier`() async throws {
|
|
60
60
|
let env = try GeminiTestEnvironment()
|
|
61
61
|
defer { env.cleanup() }
|
|
62
62
|
try env.writeCredentials(
|
|
@@ -100,7 +100,7 @@ struct GeminiStatusProbePlanTests {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
@Test
|
|
103
|
-
func
|
|
103
|
+
func `detects workspace from free tier with hosted domain`() async throws {
|
|
104
104
|
let env = try GeminiTestEnvironment()
|
|
105
105
|
defer { env.cleanup() }
|
|
106
106
|
let idToken = GeminiAPITestHelpers.makeIDToken(email: "user@company.com", hostedDomain: "company.com")
|
|
@@ -145,7 +145,7 @@ struct GeminiStatusProbePlanTests {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
@Test
|
|
148
|
-
func
|
|
148
|
+
func `detects free from free tier without hosted domain`() async throws {
|
|
149
149
|
let env = try GeminiTestEnvironment()
|
|
150
150
|
defer { env.cleanup() }
|
|
151
151
|
let idToken = GeminiAPITestHelpers.makeIDToken(email: "user@gmail.com")
|
|
@@ -190,7 +190,7 @@ struct GeminiStatusProbePlanTests {
|
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
@Test
|
|
193
|
-
func
|
|
193
|
+
func `detects legacy from legacy tier`() async throws {
|
|
194
194
|
let env = try GeminiTestEnvironment()
|
|
195
195
|
defer { env.cleanup() }
|
|
196
196
|
try env.writeCredentials(
|
|
@@ -234,7 +234,7 @@ struct GeminiStatusProbePlanTests {
|
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
@Test
|
|
237
|
-
func
|
|
237
|
+
func `leaves blank when load code assist fails`() async throws {
|
|
238
238
|
let env = try GeminiTestEnvironment()
|
|
239
239
|
defer { env.cleanup() }
|
|
240
240
|
try env.writeCredentials(
|