@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
|
@@ -17,7 +17,7 @@ struct CustomProvidersPane: View {
|
|
|
17
17
|
// Header with add button
|
|
18
18
|
HStack {
|
|
19
19
|
Text("Custom API Providers")
|
|
20
|
-
.font(.headline)
|
|
20
|
+
.font(RunicFont.headline)
|
|
21
21
|
|
|
22
22
|
Spacer()
|
|
23
23
|
|
|
@@ -37,11 +37,11 @@ struct CustomProvidersPane: View {
|
|
|
37
37
|
.foregroundStyle(.secondary)
|
|
38
38
|
|
|
39
39
|
Text("No custom providers configured")
|
|
40
|
-
.font(.headline)
|
|
40
|
+
.font(RunicFont.headline)
|
|
41
41
|
.foregroundStyle(.secondary)
|
|
42
42
|
|
|
43
43
|
Text("Add a custom API provider to track usage from APIs not natively supported by Runic.")
|
|
44
|
-
.font(.caption)
|
|
44
|
+
.font(RunicFont.caption)
|
|
45
45
|
.foregroundStyle(.tertiary)
|
|
46
46
|
.multilineTextAlignment(.center)
|
|
47
47
|
.frame(maxWidth: 300)
|
|
@@ -56,9 +56,8 @@ struct CustomProvidersPane: View {
|
|
|
56
56
|
snapshot: self.store.customProviderSnapshots[provider.id],
|
|
57
57
|
onToggle: { enabled in self.toggleProvider(provider, enabled: enabled) },
|
|
58
58
|
onEdit: { self.editingProvider = provider },
|
|
59
|
-
onDelete: { self.confirmDelete = provider }
|
|
60
|
-
|
|
61
|
-
.padding(.horizontal, PreferencesLayoutMetrics.paneHorizontal)
|
|
59
|
+
onDelete: { self.confirmDelete = provider })
|
|
60
|
+
.padding(.horizontal, PreferencesLayoutMetrics.paneHorizontal)
|
|
62
61
|
|
|
63
62
|
if provider.id != self.providers.last?.id {
|
|
64
63
|
Divider()
|
|
@@ -79,8 +78,7 @@ struct CustomProvidersPane: View {
|
|
|
79
78
|
self.addProvider(provider)
|
|
80
79
|
self.showingAddProvider = false
|
|
81
80
|
},
|
|
82
|
-
onCancel: { self.showingAddProvider = false }
|
|
83
|
-
)
|
|
81
|
+
onCancel: { self.showingAddProvider = false })
|
|
84
82
|
}
|
|
85
83
|
.sheet(item: self.$editingProvider) { provider in
|
|
86
84
|
CustomProviderEditorView(
|
|
@@ -89,13 +87,12 @@ struct CustomProvidersPane: View {
|
|
|
89
87
|
self.updateProvider(updated)
|
|
90
88
|
self.editingProvider = nil
|
|
91
89
|
},
|
|
92
|
-
onCancel: { self.editingProvider = nil }
|
|
93
|
-
)
|
|
90
|
+
onCancel: { self.editingProvider = nil })
|
|
94
91
|
}
|
|
95
92
|
.alert("Delete Provider", isPresented: Binding(
|
|
96
93
|
get: { self.confirmDelete != nil },
|
|
97
|
-
set: { if !$0 { self.confirmDelete = nil } }
|
|
98
|
-
|
|
94
|
+
set: { if !$0 { self.confirmDelete = nil } }))
|
|
95
|
+
{
|
|
99
96
|
Button("Cancel", role: .cancel) { self.confirmDelete = nil }
|
|
100
97
|
Button("Delete", role: .destructive) {
|
|
101
98
|
if let provider = self.confirmDelete {
|
|
@@ -165,40 +162,40 @@ private struct CustomProviderRow: View {
|
|
|
165
162
|
|
|
166
163
|
var body: some View {
|
|
167
164
|
HStack(spacing: RunicSpacing.sm) {
|
|
168
|
-
Image(systemName: provider.icon)
|
|
165
|
+
Image(systemName: self.provider.icon)
|
|
169
166
|
.font(.system(size: 24))
|
|
170
167
|
.foregroundStyle(self.iconColor)
|
|
171
168
|
.frame(width: 32, height: 32)
|
|
172
169
|
|
|
173
170
|
VStack(alignment: .leading, spacing: 4) {
|
|
174
|
-
Text(provider.name)
|
|
175
|
-
.font(.body)
|
|
171
|
+
Text(self.provider.name)
|
|
172
|
+
.font(RunicFont.body)
|
|
176
173
|
.fontWeight(.medium)
|
|
177
174
|
|
|
178
175
|
if let snapshot = self.snapshot {
|
|
179
176
|
if let error = snapshot.error {
|
|
180
177
|
Text(error)
|
|
181
|
-
.font(.caption)
|
|
178
|
+
.font(RunicFont.caption)
|
|
182
179
|
.foregroundStyle(.red)
|
|
183
180
|
} else {
|
|
184
181
|
HStack(spacing: 4) {
|
|
185
182
|
if let quota = snapshot.usageData.quota, let used = snapshot.usageData.used {
|
|
186
183
|
let percent = quota > 0 ? (used / quota) * 100 : 0
|
|
187
184
|
Text("\(Int(percent))% used")
|
|
188
|
-
.font(.caption)
|
|
185
|
+
.font(RunicFont.caption)
|
|
189
186
|
.foregroundStyle(.secondary)
|
|
190
187
|
}
|
|
191
188
|
Text("•")
|
|
192
|
-
.font(.caption)
|
|
189
|
+
.font(RunicFont.caption)
|
|
193
190
|
.foregroundStyle(.tertiary)
|
|
194
191
|
Text("Updated \(snapshot.updatedAt.relativeDescription())")
|
|
195
|
-
.font(.caption)
|
|
192
|
+
.font(RunicFont.caption)
|
|
196
193
|
.foregroundStyle(.tertiary)
|
|
197
194
|
}
|
|
198
195
|
}
|
|
199
196
|
} else {
|
|
200
197
|
Text("No data")
|
|
201
|
-
.font(.caption)
|
|
198
|
+
.font(RunicFont.caption)
|
|
202
199
|
.foregroundStyle(.tertiary)
|
|
203
200
|
}
|
|
204
201
|
}
|
|
@@ -222,17 +219,16 @@ private struct CustomProviderRow: View {
|
|
|
222
219
|
|
|
223
220
|
Toggle("", isOn: Binding(
|
|
224
221
|
get: { self.provider.enabled },
|
|
225
|
-
set: { self.onToggle($0) }
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
.toggleStyle(.switch)
|
|
222
|
+
set: { self.onToggle($0) }))
|
|
223
|
+
.labelsHidden()
|
|
224
|
+
.toggleStyle(.switch)
|
|
229
225
|
}
|
|
230
226
|
}
|
|
231
227
|
.padding(.vertical, RunicSpacing.sm)
|
|
232
228
|
}
|
|
233
229
|
|
|
234
230
|
private var iconColor: Color {
|
|
235
|
-
if !provider.enabled { return .secondary }
|
|
231
|
+
if !self.provider.enabled { return .secondary }
|
|
236
232
|
if let colorHex = provider.colorHex, let nsColor = NSColor(hexString: colorHex) {
|
|
237
233
|
return Color(nsColor: nsColor)
|
|
238
234
|
}
|
|
@@ -242,8 +238,8 @@ private struct CustomProviderRow: View {
|
|
|
242
238
|
|
|
243
239
|
// MARK: - Helper Extensions
|
|
244
240
|
|
|
245
|
-
|
|
246
|
-
func relativeDescription() -> String {
|
|
241
|
+
extension Date {
|
|
242
|
+
fileprivate func relativeDescription() -> String {
|
|
247
243
|
let now = Date()
|
|
248
244
|
let interval = now.timeIntervalSince(self)
|
|
249
245
|
if interval < 60 { return "just now" }
|
|
@@ -253,8 +249,8 @@ private extension Date {
|
|
|
253
249
|
}
|
|
254
250
|
}
|
|
255
251
|
|
|
256
|
-
|
|
257
|
-
convenience init?(hexString: String) {
|
|
252
|
+
extension NSColor {
|
|
253
|
+
fileprivate convenience init?(hexString: String) {
|
|
258
254
|
var hex = hexString.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
259
255
|
if hex.hasPrefix("#") { hex.removeFirst() }
|
|
260
256
|
guard hex.count == 6 else { return nil }
|
|
@@ -267,7 +263,6 @@ private extension NSColor {
|
|
|
267
263
|
}
|
|
268
264
|
}
|
|
269
265
|
|
|
270
|
-
|
|
271
266
|
// MARK: - Custom Provider Editor View (Simplified)
|
|
272
267
|
|
|
273
268
|
@MainActor
|
|
@@ -283,39 +278,43 @@ private struct CustomProviderEditorView: View {
|
|
|
283
278
|
|
|
284
279
|
var body: some View {
|
|
285
280
|
VStack {
|
|
286
|
-
Text(provider == nil ? "Add Custom Provider" : "Edit Provider")
|
|
287
|
-
.font(.headline)
|
|
281
|
+
Text(self.provider == nil ? "Add Custom Provider" : "Edit Provider")
|
|
282
|
+
.font(RunicFont.headline)
|
|
288
283
|
.padding()
|
|
289
284
|
Form {
|
|
290
|
-
TextField("Provider Name", text:
|
|
291
|
-
TextField("Icon (SF Symbol)", text:
|
|
292
|
-
SecureField("API Token", text:
|
|
293
|
-
TextField("Usage Endpoint URL", text:
|
|
285
|
+
TextField("Provider Name", text: self.$name)
|
|
286
|
+
TextField("Icon (SF Symbol)", text: self.$icon)
|
|
287
|
+
SecureField("API Token", text: self.$apiToken)
|
|
288
|
+
TextField("Usage Endpoint URL", text: self.$usageEndpointURL)
|
|
294
289
|
}
|
|
295
290
|
.padding()
|
|
296
291
|
HStack {
|
|
297
|
-
Button("Cancel") { onCancel() }
|
|
298
|
-
Button(provider == nil ? "Add" : "Save") {
|
|
292
|
+
Button("Cancel") { self.onCancel() }
|
|
293
|
+
Button(self.provider == nil ? "Add" : "Save") {
|
|
299
294
|
// Simplified save logic
|
|
300
|
-
onSave(CustomProviderConfig(
|
|
301
|
-
id: provider?.id ?? UUID().uuidString,
|
|
302
|
-
name: name,
|
|
303
|
-
icon: icon,
|
|
304
|
-
enabled: provider?.enabled ?? true,
|
|
305
|
-
auth: AuthConfig(
|
|
306
|
-
|
|
307
|
-
|
|
295
|
+
self.onSave(CustomProviderConfig(
|
|
296
|
+
id: self.provider?.id ?? UUID().uuidString,
|
|
297
|
+
name: self.name,
|
|
298
|
+
icon: self.icon,
|
|
299
|
+
enabled: self.provider?.enabled ?? true,
|
|
300
|
+
auth: AuthConfig(
|
|
301
|
+
type: .bearer,
|
|
302
|
+
headerName: "Authorization",
|
|
303
|
+
tokenKeychain: "custom-\(self.name)"),
|
|
304
|
+
endpoints: EndpointConfig(usage: UsageEndpoint(
|
|
305
|
+
url: self.usageEndpointURL,
|
|
306
|
+
mapping: ResponseMapping()))))
|
|
308
307
|
}
|
|
309
|
-
.disabled(name.isEmpty || apiToken.isEmpty || usageEndpointURL.isEmpty)
|
|
308
|
+
.disabled(self.name.isEmpty || self.apiToken.isEmpty || self.usageEndpointURL.isEmpty)
|
|
310
309
|
}
|
|
311
310
|
.padding()
|
|
312
311
|
}
|
|
313
312
|
.frame(width: 500, height: 400)
|
|
314
313
|
.onAppear {
|
|
315
314
|
if let p = provider {
|
|
316
|
-
name = p.name
|
|
317
|
-
icon = p.icon
|
|
318
|
-
usageEndpointURL = p.endpoints.usage?.url ?? ""
|
|
315
|
+
self.name = p.name
|
|
316
|
+
self.icon = p.icon
|
|
317
|
+
self.usageEndpointURL = p.endpoints.usage?.url ?? ""
|
|
319
318
|
}
|
|
320
319
|
}
|
|
321
320
|
}
|
|
@@ -128,7 +128,7 @@ struct DebugPane: View {
|
|
|
128
128
|
ZStack(alignment: .topLeading) {
|
|
129
129
|
ScrollView {
|
|
130
130
|
Text(self.displayedLog)
|
|
131
|
-
.font(.
|
|
131
|
+
.font(RunicFont.footnote)
|
|
132
132
|
.textSelection(.enabled)
|
|
133
133
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
134
134
|
.padding(RunicSpacing.xs)
|
|
@@ -160,7 +160,7 @@ struct DebugPane: View {
|
|
|
160
160
|
|
|
161
161
|
ScrollView {
|
|
162
162
|
Text(self.fetchAttemptsText(for: self.currentFetchProvider))
|
|
163
|
-
.font(.
|
|
163
|
+
.font(RunicFont.footnote)
|
|
164
164
|
.textSelection(.enabled)
|
|
165
165
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
166
166
|
.padding(RunicSpacing.xs)
|
|
@@ -185,7 +185,7 @@ struct DebugPane: View {
|
|
|
185
185
|
Text(self.store.openAIDashboardCookieImportDebugLog?.isEmpty == false
|
|
186
186
|
? (self.store.openAIDashboardCookieImportDebugLog ?? "")
|
|
187
187
|
: "No log yet. Enable \"Access OpenAI via web\" in General to run an import.")
|
|
188
|
-
.font(.
|
|
188
|
+
.font(RunicFont.footnote)
|
|
189
189
|
.textSelection(.enabled)
|
|
190
190
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
191
191
|
.padding(RunicSpacing.xs)
|
|
@@ -212,7 +212,7 @@ struct DebugPane: View {
|
|
|
212
212
|
|
|
213
213
|
if let status = self.costCacheStatus {
|
|
214
214
|
Text(status)
|
|
215
|
-
.font(.footnote)
|
|
215
|
+
.font(RunicFont.footnote)
|
|
216
216
|
.foregroundStyle(.tertiary)
|
|
217
217
|
}
|
|
218
218
|
}
|
|
@@ -313,12 +313,12 @@ struct DebugPane: View {
|
|
|
313
313
|
|
|
314
314
|
VStack(alignment: .leading, spacing: RunicSpacing.xs) {
|
|
315
315
|
Text("Effective PATH")
|
|
316
|
-
.font(.callout.weight(.semibold))
|
|
316
|
+
.font(RunicFont.callout.weight(.semibold))
|
|
317
317
|
ScrollView {
|
|
318
318
|
Text(self.store.pathDebugInfo.effectivePATH.isEmpty
|
|
319
319
|
? "Unavailable"
|
|
320
320
|
: self.store.pathDebugInfo.effectivePATH)
|
|
321
|
-
.font(.
|
|
321
|
+
.font(RunicFont.footnote)
|
|
322
322
|
.textSelection(.enabled)
|
|
323
323
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
324
324
|
.padding(RunicSpacing.xs)
|
|
@@ -331,10 +331,10 @@ struct DebugPane: View {
|
|
|
331
331
|
if let loginPATH = self.store.pathDebugInfo.loginShellPATH {
|
|
332
332
|
VStack(alignment: .leading, spacing: RunicSpacing.xs) {
|
|
333
333
|
Text("Login shell PATH (startup capture)")
|
|
334
|
-
.font(.callout.weight(.semibold))
|
|
334
|
+
.font(RunicFont.callout.weight(.semibold))
|
|
335
335
|
ScrollView {
|
|
336
336
|
Text(loginPATH)
|
|
337
|
-
.font(.
|
|
337
|
+
.font(RunicFont.footnote)
|
|
338
338
|
.textSelection(.enabled)
|
|
339
339
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
340
340
|
.padding(RunicSpacing.xs)
|
|
@@ -405,9 +405,9 @@ struct DebugPane: View {
|
|
|
405
405
|
private func binaryRow(title: String, value: String?) -> some View {
|
|
406
406
|
VStack(alignment: .leading, spacing: RunicSpacing.xs) {
|
|
407
407
|
Text(title)
|
|
408
|
-
.font(.callout.weight(.semibold))
|
|
408
|
+
.font(RunicFont.callout.weight(.semibold))
|
|
409
409
|
Text(value ?? "Not found")
|
|
410
|
-
.font(.
|
|
410
|
+
.font(RunicFont.footnote)
|
|
411
411
|
.foregroundStyle(value == nil ? .secondary : .primary)
|
|
412
412
|
}
|
|
413
413
|
}
|
|
@@ -23,18 +23,18 @@ struct GeneralPane: View {
|
|
|
23
23
|
VStack(alignment: .leading, spacing: RunicSpacing.xxs) {
|
|
24
24
|
Toggle(isOn: self.$settings.costUsageEnabled) {
|
|
25
25
|
Text("Show cost summary")
|
|
26
|
-
.font(.body)
|
|
26
|
+
.font(RunicFont.body)
|
|
27
27
|
}
|
|
28
28
|
.toggleStyle(.checkbox)
|
|
29
29
|
|
|
30
30
|
Text("Reads local usage logs. Shows today + last 30 days cost in the menu.")
|
|
31
|
-
.font(.footnote)
|
|
31
|
+
.font(RunicFont.footnote)
|
|
32
32
|
.foregroundStyle(.tertiary)
|
|
33
33
|
.fixedSize(horizontal: false, vertical: true)
|
|
34
34
|
|
|
35
35
|
if self.settings.costUsageEnabled {
|
|
36
36
|
Text("Auto-refresh: hourly · Timeout: 10m")
|
|
37
|
-
.font(.footnote)
|
|
37
|
+
.font(RunicFont.footnote)
|
|
38
38
|
.foregroundStyle(.tertiary)
|
|
39
39
|
|
|
40
40
|
self.costStatusLine(provider: .claude)
|
|
@@ -45,12 +45,12 @@ struct GeneralPane: View {
|
|
|
45
45
|
VStack(alignment: .leading, spacing: RunicSpacing.xxs) {
|
|
46
46
|
Toggle(isOn: self.$settings.openAIWebAccessEnabled) {
|
|
47
47
|
Text("Access OpenAI via web")
|
|
48
|
-
.font(.body)
|
|
48
|
+
.font(RunicFont.body)
|
|
49
49
|
}
|
|
50
50
|
.toggleStyle(.checkbox)
|
|
51
51
|
|
|
52
52
|
Text("Imports browser cookies for dashboard extras (credits history, code review).")
|
|
53
|
-
.font(.footnote)
|
|
53
|
+
.font(RunicFont.footnote)
|
|
54
54
|
.foregroundStyle(.tertiary)
|
|
55
55
|
.fixedSize(horizontal: false, vertical: true)
|
|
56
56
|
}
|
|
@@ -84,7 +84,7 @@ struct GeneralPane: View {
|
|
|
84
84
|
VStack(alignment: .leading, spacing: RunicSpacing.sm) {
|
|
85
85
|
VStack(alignment: .leading, spacing: RunicSpacing.xxs) {
|
|
86
86
|
Text("Menu refresh rate")
|
|
87
|
-
.font(.body)
|
|
87
|
+
.font(RunicFont.body)
|
|
88
88
|
|
|
89
89
|
Picker("", selection: self.$settings.refreshFrequency) {
|
|
90
90
|
ForEach(RefreshFrequency.allCases) { option in
|
|
@@ -94,13 +94,13 @@ struct GeneralPane: View {
|
|
|
94
94
|
.pickerStyle(.segmented)
|
|
95
95
|
|
|
96
96
|
Text("How often to automatically refresh usage data.")
|
|
97
|
-
.font(.footnote)
|
|
97
|
+
.font(RunicFont.footnote)
|
|
98
98
|
.foregroundStyle(.tertiary)
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
VStack(alignment: .leading, spacing: RunicSpacing.xxs) {
|
|
102
102
|
Text("Chart style")
|
|
103
|
-
.font(.body)
|
|
103
|
+
.font(RunicFont.body)
|
|
104
104
|
|
|
105
105
|
Picker("", selection: self.$settings.chartStyle) {
|
|
106
106
|
Text("Line").tag(ChartStyle.line)
|
|
@@ -111,13 +111,13 @@ struct GeneralPane: View {
|
|
|
111
111
|
.frame(maxWidth: 360)
|
|
112
112
|
|
|
113
113
|
Text("Visual style for usage charts and graphs.")
|
|
114
|
-
.font(.footnote)
|
|
114
|
+
.font(RunicFont.footnote)
|
|
115
115
|
.foregroundStyle(.tertiary)
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
VStack(alignment: .leading, spacing: RunicSpacing.xxs) {
|
|
119
119
|
Text("Number format")
|
|
120
|
-
.font(.body)
|
|
120
|
+
.font(RunicFont.body)
|
|
121
121
|
|
|
122
122
|
Picker("", selection: self.$settings.numberFormat) {
|
|
123
123
|
Text("Abbreviated (45.2K)").tag(NumberFormat.abbreviated)
|
|
@@ -127,13 +127,13 @@ struct GeneralPane: View {
|
|
|
127
127
|
.frame(maxWidth: 360)
|
|
128
128
|
|
|
129
129
|
Text("How to display large numbers in the UI.")
|
|
130
|
-
.font(.footnote)
|
|
130
|
+
.font(RunicFont.footnote)
|
|
131
131
|
.foregroundStyle(.tertiary)
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
VStack(alignment: .leading, spacing: RunicSpacing.xxs) {
|
|
135
135
|
Text("Date format")
|
|
136
|
-
.font(.body)
|
|
136
|
+
.font(RunicFont.body)
|
|
137
137
|
|
|
138
138
|
Picker("", selection: self.$settings.dateFormat) {
|
|
139
139
|
Text("Relative (2h ago)").tag(DateFormat.relative)
|
|
@@ -143,13 +143,13 @@ struct GeneralPane: View {
|
|
|
143
143
|
.frame(maxWidth: 360)
|
|
144
144
|
|
|
145
145
|
Text("How to display timestamps throughout the app.")
|
|
146
|
-
.font(.footnote)
|
|
146
|
+
.font(RunicFont.footnote)
|
|
147
147
|
.foregroundStyle(.tertiary)
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
VStack(alignment: .leading, spacing: RunicSpacing.xxs) {
|
|
151
151
|
Text("Theme")
|
|
152
|
-
.font(.body)
|
|
152
|
+
.font(RunicFont.body)
|
|
153
153
|
|
|
154
154
|
Picker("", selection: self.$settings.theme) {
|
|
155
155
|
Text("System").tag(Theme.system)
|
|
@@ -160,7 +160,26 @@ struct GeneralPane: View {
|
|
|
160
160
|
.frame(maxWidth: 360)
|
|
161
161
|
|
|
162
162
|
Text("App appearance (requires restart).")
|
|
163
|
-
.font(.footnote)
|
|
163
|
+
.font(RunicFont.footnote)
|
|
164
|
+
.foregroundStyle(.tertiary)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
VStack(alignment: .leading, spacing: RunicSpacing.xxs) {
|
|
168
|
+
Text("Font")
|
|
169
|
+
.font(RunicFont.body)
|
|
170
|
+
|
|
171
|
+
Picker("", selection: self.$settings.selectedFontFamily) {
|
|
172
|
+
ForEach(RunicFontChoice.availableChoices()) { choice in
|
|
173
|
+
Text(choice.displayName)
|
|
174
|
+
.font(choice.previewFont)
|
|
175
|
+
.tag(choice.id)
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
.pickerStyle(.menu)
|
|
179
|
+
.frame(maxWidth: 360)
|
|
180
|
+
|
|
181
|
+
Text("Drop .ttf/.otf files in Resources/Fonts to add more.")
|
|
182
|
+
.font(RunicFont.footnote)
|
|
164
183
|
.foregroundStyle(.tertiary)
|
|
165
184
|
}
|
|
166
185
|
}
|
|
@@ -186,7 +205,7 @@ struct GeneralPane: View {
|
|
|
186
205
|
|
|
187
206
|
guard provider == .claude || provider == .codex else {
|
|
188
207
|
return Text("\(name): unsupported")
|
|
189
|
-
.font(.footnote)
|
|
208
|
+
.font(RunicFont.footnote)
|
|
190
209
|
.foregroundStyle(.tertiary)
|
|
191
210
|
}
|
|
192
211
|
|
|
@@ -200,20 +219,20 @@ struct GeneralPane: View {
|
|
|
200
219
|
return formatter.string(from: seconds).map { " (\($0))" } ?? ""
|
|
201
220
|
}()
|
|
202
221
|
return Text("\(name): fetching…\(elapsed)")
|
|
203
|
-
.font(.footnote)
|
|
222
|
+
.font(RunicFont.footnote)
|
|
204
223
|
.foregroundStyle(.tertiary)
|
|
205
224
|
}
|
|
206
225
|
if let snapshot = self.store.tokenSnapshot(for: provider) {
|
|
207
226
|
let updated = UsageFormatter.updatedString(from: snapshot.updatedAt)
|
|
208
227
|
let cost = snapshot.last30DaysCostUSD.map { UsageFormatter.usdString($0) } ?? "—"
|
|
209
228
|
return Text("\(name): \(updated) · 30d \(cost)")
|
|
210
|
-
.font(.footnote)
|
|
229
|
+
.font(RunicFont.footnote)
|
|
211
230
|
.foregroundStyle(.tertiary)
|
|
212
231
|
}
|
|
213
232
|
if let error = self.store.tokenError(for: provider), !error.isEmpty {
|
|
214
233
|
let truncated = UsageFormatter.truncatedSingleLine(error, max: 120)
|
|
215
234
|
return Text("\(name): \(truncated)")
|
|
216
|
-
.font(.footnote)
|
|
235
|
+
.font(RunicFont.footnote)
|
|
217
236
|
.foregroundStyle(.tertiary)
|
|
218
237
|
}
|
|
219
238
|
if let lastAttempt = self.store.tokenLastAttemptAt(for: provider) {
|
|
@@ -221,11 +240,11 @@ struct GeneralPane: View {
|
|
|
221
240
|
rel.unitsStyle = .abbreviated
|
|
222
241
|
let when = rel.localizedString(for: lastAttempt, relativeTo: Date())
|
|
223
242
|
return Text("\(name): last attempt \(when)")
|
|
224
|
-
.font(.footnote)
|
|
243
|
+
.font(RunicFont.footnote)
|
|
225
244
|
.foregroundStyle(.tertiary)
|
|
226
245
|
}
|
|
227
246
|
return Text("\(name): no data yet")
|
|
228
|
-
.font(.footnote)
|
|
247
|
+
.font(RunicFont.footnote)
|
|
229
248
|
.foregroundStyle(.tertiary)
|
|
230
249
|
}
|
|
231
250
|
}
|
|
@@ -7,22 +7,22 @@ struct HelpPane: View {
|
|
|
7
7
|
PreferencesPane {
|
|
8
8
|
SettingsSection(contentSpacing: PreferencesLayoutMetrics.sectionSpacing) {
|
|
9
9
|
Text("Menu refresh")
|
|
10
|
-
.font(.caption)
|
|
10
|
+
.font(RunicFont.caption)
|
|
11
11
|
.foregroundStyle(.secondary)
|
|
12
12
|
.textCase(.uppercase)
|
|
13
13
|
|
|
14
14
|
Text("Use Ping now in the menu to update usage without closing the panel.")
|
|
15
|
-
.font(.body)
|
|
15
|
+
.font(RunicFont.body)
|
|
16
16
|
.foregroundStyle(.secondary)
|
|
17
17
|
.fixedSize(horizontal: false, vertical: true)
|
|
18
18
|
|
|
19
19
|
Text("Auto-refresh cadence and safety rules live in Performance > Refresh & Safety.")
|
|
20
|
-
.font(.body)
|
|
20
|
+
.font(RunicFont.body)
|
|
21
21
|
.foregroundStyle(.secondary)
|
|
22
22
|
.fixedSize(horizontal: false, vertical: true)
|
|
23
23
|
|
|
24
24
|
Text("Manual mode avoids background refreshes that may touch tokens.")
|
|
25
|
-
.font(.body)
|
|
25
|
+
.font(RunicFont.body)
|
|
26
26
|
.foregroundStyle(.secondary)
|
|
27
27
|
.fixedSize(horizontal: false, vertical: true)
|
|
28
28
|
}
|
|
@@ -31,17 +31,17 @@ struct HelpPane: View {
|
|
|
31
31
|
|
|
32
32
|
SettingsSection(contentSpacing: PreferencesLayoutMetrics.sectionSpacing) {
|
|
33
33
|
Text("Data sources")
|
|
34
|
-
.font(.caption)
|
|
34
|
+
.font(RunicFont.caption)
|
|
35
35
|
.foregroundStyle(.secondary)
|
|
36
36
|
.textCase(.uppercase)
|
|
37
37
|
|
|
38
38
|
Text("Runic reads local logs or browser cookies depending on provider settings.")
|
|
39
|
-
.font(.body)
|
|
39
|
+
.font(RunicFont.body)
|
|
40
40
|
.foregroundStyle(.secondary)
|
|
41
41
|
.fixedSize(horizontal: false, vertical: true)
|
|
42
42
|
|
|
43
43
|
Text("Open Providers to review each source and add credentials.")
|
|
44
|
-
.font(.body)
|
|
44
|
+
.font(RunicFont.body)
|
|
45
45
|
.foregroundStyle(.secondary)
|
|
46
46
|
.fixedSize(horizontal: false, vertical: true)
|
|
47
47
|
}
|