@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
|
@@ -5,7 +5,6 @@ import SwiftUI
|
|
|
5
5
|
/// Performance monitoring dashboard with quality metrics, latency charts, and error tracking
|
|
6
6
|
@MainActor
|
|
7
7
|
struct PerformanceDashboardView: View {
|
|
8
|
-
|
|
9
8
|
// MARK: - Types
|
|
10
9
|
|
|
11
10
|
enum TimeRange: String, CaseIterable, Identifiable {
|
|
@@ -13,15 +12,19 @@ struct PerformanceDashboardView: View {
|
|
|
13
12
|
case days7 = "7d"
|
|
14
13
|
case days30 = "30d"
|
|
15
14
|
|
|
16
|
-
var id: String {
|
|
15
|
+
var id: String {
|
|
16
|
+
self.rawValue
|
|
17
|
+
}
|
|
17
18
|
|
|
18
|
-
var displayName: String {
|
|
19
|
+
var displayName: String {
|
|
20
|
+
self.rawValue
|
|
21
|
+
}
|
|
19
22
|
|
|
20
23
|
var days: Int {
|
|
21
24
|
switch self {
|
|
22
|
-
case .day24h:
|
|
23
|
-
case .days7:
|
|
24
|
-
case .days30:
|
|
25
|
+
case .day24h: 1
|
|
26
|
+
case .days7: 7
|
|
27
|
+
case .days30: 30
|
|
25
28
|
}
|
|
26
29
|
}
|
|
27
30
|
}
|
|
@@ -72,6 +75,7 @@ struct PerformanceDashboardView: View {
|
|
|
72
75
|
}
|
|
73
76
|
.padding(RunicSpacing.md)
|
|
74
77
|
}
|
|
78
|
+
.runicTypography()
|
|
75
79
|
.frame(width: self.width)
|
|
76
80
|
.task {
|
|
77
81
|
await self.loadData()
|
|
@@ -92,7 +96,7 @@ struct PerformanceDashboardView: View {
|
|
|
92
96
|
private var headerSection: some View {
|
|
93
97
|
VStack(alignment: .leading, spacing: RunicSpacing.xs) {
|
|
94
98
|
Text("Performance Dashboard")
|
|
95
|
-
.font(.title2)
|
|
99
|
+
.font(RunicFont.title2)
|
|
96
100
|
.fontWeight(.bold)
|
|
97
101
|
|
|
98
102
|
HStack(spacing: RunicSpacing.sm) {
|
|
@@ -136,7 +140,7 @@ struct PerformanceDashboardView: View {
|
|
|
136
140
|
}
|
|
137
141
|
|
|
138
142
|
private var availableModels: [String] {
|
|
139
|
-
let models = self.stats.compactMap
|
|
143
|
+
let models = self.stats.compactMap(\.model).filter { !$0.isEmpty }
|
|
140
144
|
return Array(Set(models)).sorted()
|
|
141
145
|
}
|
|
142
146
|
|
|
@@ -145,7 +149,7 @@ struct PerformanceDashboardView: View {
|
|
|
145
149
|
private var metricsSection: some View {
|
|
146
150
|
VStack(alignment: .leading, spacing: RunicSpacing.xs) {
|
|
147
151
|
Text("Key Metrics")
|
|
148
|
-
.font(.headline)
|
|
152
|
+
.font(RunicFont.headline)
|
|
149
153
|
.fontWeight(.semibold)
|
|
150
154
|
|
|
151
155
|
let aggregated = self.aggregateStats()
|
|
@@ -181,12 +185,12 @@ struct PerformanceDashboardView: View {
|
|
|
181
185
|
private var latencyChartSection: some View {
|
|
182
186
|
VStack(alignment: .leading, spacing: RunicSpacing.xs) {
|
|
183
187
|
Text("Latency Over Time")
|
|
184
|
-
.font(.headline)
|
|
188
|
+
.font(RunicFont.headline)
|
|
185
189
|
.fontWeight(.semibold)
|
|
186
190
|
|
|
187
191
|
if self.stats.isEmpty {
|
|
188
192
|
Text("No latency data available")
|
|
189
|
-
.font(.footnote)
|
|
193
|
+
.font(RunicFont.footnote)
|
|
190
194
|
.foregroundStyle(.secondary)
|
|
191
195
|
.frame(height: 150)
|
|
192
196
|
} else {
|
|
@@ -213,7 +217,7 @@ struct PerformanceDashboardView: View {
|
|
|
213
217
|
.chartXAxis {
|
|
214
218
|
AxisMarks(values: .automatic(desiredCount: 5)) { _ in
|
|
215
219
|
AxisValueLabel(format: .dateTime.month(.abbreviated).day())
|
|
216
|
-
.font(.caption2)
|
|
220
|
+
.font(RunicFont.caption2)
|
|
217
221
|
AxisGridLine()
|
|
218
222
|
}
|
|
219
223
|
}
|
|
@@ -224,13 +228,13 @@ struct PerformanceDashboardView: View {
|
|
|
224
228
|
if self.hasPercentileData {
|
|
225
229
|
HStack(spacing: RunicSpacing.sm) {
|
|
226
230
|
Text("Line: Avg")
|
|
227
|
-
.font(.caption)
|
|
231
|
+
.font(RunicFont.caption)
|
|
228
232
|
.foregroundStyle(.secondary)
|
|
229
233
|
Text("•")
|
|
230
|
-
.font(.caption)
|
|
234
|
+
.font(RunicFont.caption)
|
|
231
235
|
.foregroundStyle(.secondary)
|
|
232
236
|
Text("Area: P95")
|
|
233
|
-
.font(.caption)
|
|
237
|
+
.font(RunicFont.caption)
|
|
234
238
|
.foregroundStyle(.secondary)
|
|
235
239
|
}
|
|
236
240
|
}
|
|
@@ -242,12 +246,12 @@ struct PerformanceDashboardView: View {
|
|
|
242
246
|
private var errorRateChartSection: some View {
|
|
243
247
|
VStack(alignment: .leading, spacing: RunicSpacing.xs) {
|
|
244
248
|
Text("Error Rate Over Time")
|
|
245
|
-
.font(.headline)
|
|
249
|
+
.font(RunicFont.headline)
|
|
246
250
|
.fontWeight(.semibold)
|
|
247
251
|
|
|
248
252
|
if self.stats.isEmpty {
|
|
249
253
|
Text("No error data available")
|
|
250
|
-
.font(.footnote)
|
|
254
|
+
.font(RunicFont.footnote)
|
|
251
255
|
.foregroundStyle(.secondary)
|
|
252
256
|
.frame(height: 150)
|
|
253
257
|
} else {
|
|
@@ -271,7 +275,7 @@ struct PerformanceDashboardView: View {
|
|
|
271
275
|
.chartXAxis {
|
|
272
276
|
AxisMarks(values: .automatic(desiredCount: 5)) { _ in
|
|
273
277
|
AxisValueLabel(format: .dateTime.month(.abbreviated).day())
|
|
274
|
-
.font(.caption2)
|
|
278
|
+
.font(RunicFont.caption2)
|
|
275
279
|
AxisGridLine()
|
|
276
280
|
}
|
|
277
281
|
}
|
|
@@ -290,7 +294,7 @@ struct PerformanceDashboardView: View {
|
|
|
290
294
|
return VStack(alignment: .leading, spacing: RunicSpacing.xxs) {
|
|
291
295
|
if hasErrors {
|
|
292
296
|
Text("Error Breakdown")
|
|
293
|
-
.font(.caption)
|
|
297
|
+
.font(RunicFont.caption)
|
|
294
298
|
.fontWeight(.medium)
|
|
295
299
|
.foregroundStyle(.secondary)
|
|
296
300
|
|
|
@@ -317,32 +321,32 @@ struct PerformanceDashboardView: View {
|
|
|
317
321
|
private var qualityRatingSection: some View {
|
|
318
322
|
VStack(alignment: .leading, spacing: RunicSpacing.xs) {
|
|
319
323
|
Text("Quality Ratings")
|
|
320
|
-
.font(.headline)
|
|
324
|
+
.font(RunicFont.headline)
|
|
321
325
|
.fontWeight(.semibold)
|
|
322
326
|
|
|
323
327
|
let aggregated = self.aggregateStats()
|
|
324
328
|
|
|
325
329
|
if aggregated.totalRatings == 0 {
|
|
326
330
|
Text("No quality ratings yet")
|
|
327
|
-
.font(.footnote)
|
|
331
|
+
.font(RunicFont.footnote)
|
|
328
332
|
.foregroundStyle(.secondary)
|
|
329
333
|
.frame(height: 100)
|
|
330
334
|
} else {
|
|
331
335
|
VStack(alignment: .leading, spacing: RunicSpacing.sm) {
|
|
332
336
|
HStack {
|
|
333
337
|
Text("Average Rating:")
|
|
334
|
-
.font(.subheadline)
|
|
338
|
+
.font(RunicFont.subheadline)
|
|
335
339
|
.foregroundStyle(.secondary)
|
|
336
340
|
|
|
337
341
|
if let avg = aggregated.avgQualityRating {
|
|
338
342
|
HStack(spacing: 4) {
|
|
339
343
|
ForEach(1...5, id: \.self) { star in
|
|
340
344
|
Image(systemName: star <= Int(avg.rounded()) ? "star.fill" : "star")
|
|
341
|
-
.font(.caption)
|
|
345
|
+
.font(RunicFont.caption)
|
|
342
346
|
.foregroundStyle(.yellow)
|
|
343
347
|
}
|
|
344
348
|
Text(String(format: "%.1f", avg))
|
|
345
|
-
.font(.subheadline)
|
|
349
|
+
.font(RunicFont.subheadline)
|
|
346
350
|
.fontWeight(.medium)
|
|
347
351
|
}
|
|
348
352
|
}
|
|
@@ -350,7 +354,7 @@ struct PerformanceDashboardView: View {
|
|
|
350
354
|
Spacer()
|
|
351
355
|
|
|
352
356
|
Text("\(aggregated.totalRatings) ratings")
|
|
353
|
-
.font(.caption)
|
|
357
|
+
.font(RunicFont.caption)
|
|
354
358
|
.foregroundStyle(.secondary)
|
|
355
359
|
}
|
|
356
360
|
|
|
@@ -370,12 +374,12 @@ struct PerformanceDashboardView: View {
|
|
|
370
374
|
|
|
371
375
|
HStack(spacing: RunicSpacing.xs) {
|
|
372
376
|
Text("\(rating)")
|
|
373
|
-
.font(.caption2)
|
|
377
|
+
.font(RunicFont.caption2)
|
|
374
378
|
.foregroundStyle(.secondary)
|
|
375
379
|
.frame(width: 12)
|
|
376
380
|
|
|
377
381
|
Image(systemName: "star.fill")
|
|
378
|
-
.font(.caption2)
|
|
382
|
+
.font(RunicFont.caption2)
|
|
379
383
|
.foregroundStyle(.yellow)
|
|
380
384
|
|
|
381
385
|
GeometryReader { geo in
|
|
@@ -391,7 +395,7 @@ struct PerformanceDashboardView: View {
|
|
|
391
395
|
.frame(height: 6)
|
|
392
396
|
|
|
393
397
|
Text("\(count)")
|
|
394
|
-
.font(.caption2)
|
|
398
|
+
.font(RunicFont.caption2)
|
|
395
399
|
.foregroundStyle(.secondary)
|
|
396
400
|
.frame(width: 30, alignment: .trailing)
|
|
397
401
|
}
|
|
@@ -401,12 +405,12 @@ struct PerformanceDashboardView: View {
|
|
|
401
405
|
|
|
402
406
|
private func ratingCount(_ rating: Int, from aggregated: AggregatedStats) -> Int {
|
|
403
407
|
switch rating {
|
|
404
|
-
case 1:
|
|
405
|
-
case 2:
|
|
406
|
-
case 3:
|
|
407
|
-
case 4:
|
|
408
|
-
case 5:
|
|
409
|
-
default:
|
|
408
|
+
case 1: aggregated.rating1Count
|
|
409
|
+
case 2: aggregated.rating2Count
|
|
410
|
+
case 3: aggregated.rating3Count
|
|
411
|
+
case 4: aggregated.rating4Count
|
|
412
|
+
case 5: aggregated.rating5Count
|
|
413
|
+
default: 0
|
|
410
414
|
}
|
|
411
415
|
}
|
|
412
416
|
|
|
@@ -417,7 +421,7 @@ struct PerformanceDashboardView: View {
|
|
|
417
421
|
ProgressView()
|
|
418
422
|
.controlSize(.regular)
|
|
419
423
|
Text("Loading performance data...")
|
|
420
|
-
.font(.subheadline)
|
|
424
|
+
.font(RunicFont.subheadline)
|
|
421
425
|
.foregroundStyle(.secondary)
|
|
422
426
|
}
|
|
423
427
|
.frame(maxWidth: .infinity, minHeight: 200)
|
|
@@ -426,12 +430,12 @@ struct PerformanceDashboardView: View {
|
|
|
426
430
|
private func errorView(_ message: String) -> some View {
|
|
427
431
|
VStack(spacing: RunicSpacing.sm) {
|
|
428
432
|
Image(systemName: "exclamationmark.triangle")
|
|
429
|
-
.font(.largeTitle)
|
|
433
|
+
.font(RunicFont.largeTitle)
|
|
430
434
|
.foregroundStyle(.red)
|
|
431
435
|
Text("Error Loading Data")
|
|
432
|
-
.font(.headline)
|
|
436
|
+
.font(RunicFont.headline)
|
|
433
437
|
Text(message)
|
|
434
|
-
.font(.subheadline)
|
|
438
|
+
.font(RunicFont.subheadline)
|
|
435
439
|
.foregroundStyle(.secondary)
|
|
436
440
|
.multilineTextAlignment(.center)
|
|
437
441
|
Button("Retry") {
|
|
@@ -444,12 +448,12 @@ struct PerformanceDashboardView: View {
|
|
|
444
448
|
private var emptyStateView: some View {
|
|
445
449
|
VStack(spacing: RunicSpacing.sm) {
|
|
446
450
|
Image(systemName: "chart.line.uptrend.xyaxis")
|
|
447
|
-
.font(.largeTitle)
|
|
451
|
+
.font(RunicFont.largeTitle)
|
|
448
452
|
.foregroundStyle(.secondary)
|
|
449
453
|
Text("No Data Available")
|
|
450
|
-
.font(.headline)
|
|
454
|
+
.font(RunicFont.headline)
|
|
451
455
|
Text("Performance data will appear here once you start using AI providers")
|
|
452
|
-
.font(.subheadline)
|
|
456
|
+
.font(RunicFont.subheadline)
|
|
453
457
|
.foregroundStyle(.secondary)
|
|
454
458
|
.multilineTextAlignment(.center)
|
|
455
459
|
}
|
|
@@ -467,8 +471,7 @@ struct PerformanceDashboardView: View {
|
|
|
467
471
|
self.stats = try await storage.fetchDailyStats(
|
|
468
472
|
timeRange: self.selection.timeRange.days,
|
|
469
473
|
provider: self.selection.provider,
|
|
470
|
-
model: self.selection.model
|
|
471
|
-
)
|
|
474
|
+
model: self.selection.model)
|
|
472
475
|
} catch {
|
|
473
476
|
self.errorMessage = error.localizedDescription
|
|
474
477
|
}
|
|
@@ -582,14 +585,14 @@ private struct MetricCard: View {
|
|
|
582
585
|
VStack(alignment: .leading, spacing: RunicSpacing.xxs) {
|
|
583
586
|
HStack {
|
|
584
587
|
Image(systemName: self.icon)
|
|
585
|
-
.font(.caption)
|
|
588
|
+
.font(RunicFont.caption)
|
|
586
589
|
.foregroundStyle(self.color)
|
|
587
590
|
Text(self.title)
|
|
588
|
-
.font(.caption)
|
|
591
|
+
.font(RunicFont.caption)
|
|
589
592
|
.foregroundStyle(.secondary)
|
|
590
593
|
}
|
|
591
594
|
Text(self.value)
|
|
592
|
-
.font(.title3)
|
|
595
|
+
.font(RunicFont.title3)
|
|
593
596
|
.fontWeight(.semibold)
|
|
594
597
|
.foregroundStyle(self.color)
|
|
595
598
|
}
|
|
@@ -611,7 +614,7 @@ private struct ErrorTypeLabel: View {
|
|
|
611
614
|
.fill(self.color)
|
|
612
615
|
.frame(width: 8, height: 8)
|
|
613
616
|
Text("\(self.type): \(self.count)")
|
|
614
|
-
.font(.caption2)
|
|
617
|
+
.font(RunicFont.caption2)
|
|
615
618
|
.foregroundStyle(.secondary)
|
|
616
619
|
}
|
|
617
620
|
}
|
|
@@ -85,7 +85,13 @@ private struct ShimmerSweep: View {
|
|
|
85
85
|
GeometryReader { geo in
|
|
86
86
|
if !self.reduceMotion {
|
|
87
87
|
LinearGradient(
|
|
88
|
-
colors: [
|
|
88
|
+
colors: [
|
|
89
|
+
.clear,
|
|
90
|
+
Color.primary.opacity(0.04),
|
|
91
|
+
Color.primary.opacity(0.07),
|
|
92
|
+
Color.primary.opacity(0.04),
|
|
93
|
+
.clear,
|
|
94
|
+
],
|
|
89
95
|
startPoint: .leading,
|
|
90
96
|
endPoint: .trailing)
|
|
91
97
|
.frame(width: geo.size.width * 0.35)
|
|
@@ -99,8 +105,8 @@ private struct ShimmerSweep: View {
|
|
|
99
105
|
guard !self.reduceMotion else { return }
|
|
100
106
|
withAnimation(
|
|
101
107
|
.easeInOut(duration: 2.8)
|
|
102
|
-
|
|
103
|
-
|
|
108
|
+
.repeatForever(autoreverses: false)
|
|
109
|
+
.delay(self.stableDelay))
|
|
104
110
|
{
|
|
105
111
|
self.offset = 1.4
|
|
106
112
|
}
|
|
@@ -125,7 +131,7 @@ private struct RotatingGradientBorder: View {
|
|
|
125
131
|
]
|
|
126
132
|
|
|
127
133
|
var body: some View {
|
|
128
|
-
if self.isActive
|
|
134
|
+
if self.isActive, !self.reduceMotion {
|
|
129
135
|
TimelineView(.animation(minimumInterval: 1 / 60.0, paused: !self.isActive)) { timeline in
|
|
130
136
|
let rotation = timeline.date.timeIntervalSinceReferenceDate * 72
|
|
131
137
|
RoundedRectangle(cornerRadius: self.cornerRadius, style: .continuous)
|
|
@@ -195,7 +201,7 @@ private struct LiquidGlassCore: ViewModifier {
|
|
|
195
201
|
Color.clear
|
|
196
202
|
.onContinuousHover { phase in
|
|
197
203
|
switch phase {
|
|
198
|
-
case .active(
|
|
204
|
+
case let .active(pt):
|
|
199
205
|
self.hovering = true
|
|
200
206
|
self.cursorUnit = UnitPoint(x: pt.x, y: pt.y)
|
|
201
207
|
case .ended:
|
|
@@ -203,8 +209,7 @@ private struct LiquidGlassCore: ViewModifier {
|
|
|
203
209
|
}
|
|
204
210
|
}
|
|
205
211
|
.frame(width: geo.size.width, height: geo.size.height)
|
|
206
|
-
}
|
|
207
|
-
)
|
|
212
|
+
})
|
|
208
213
|
}
|
|
209
214
|
}
|
|
210
215
|
|
|
@@ -224,7 +229,7 @@ struct LiquidSection<Content: View>: View {
|
|
|
224
229
|
VStack(alignment: .leading, spacing: RunicSpacing.sm) {
|
|
225
230
|
if let title {
|
|
226
231
|
Text(title)
|
|
227
|
-
.font(.
|
|
232
|
+
.font(RunicFont.caption.weight(.semibold))
|
|
228
233
|
.foregroundStyle(.secondary)
|
|
229
234
|
.textCase(.uppercase)
|
|
230
235
|
.padding(.leading, RunicSpacing.xxs)
|
|
@@ -237,11 +242,7 @@ struct LiquidSection<Content: View>: View {
|
|
|
237
242
|
|
|
238
243
|
@MainActor
|
|
239
244
|
struct GlassCard<Content: View>: View {
|
|
240
|
-
let content: Content
|
|
241
|
-
|
|
242
|
-
init(@ViewBuilder content: () -> Content) {
|
|
243
|
-
self.content = content()
|
|
244
|
-
}
|
|
245
|
+
@ViewBuilder let content: Content
|
|
245
246
|
|
|
246
247
|
var body: some View {
|
|
247
248
|
self.content
|
|
@@ -263,7 +264,7 @@ extension View {
|
|
|
263
264
|
.scaleEffect(appeared ? 1 : 0.97, anchor: .top)
|
|
264
265
|
.animation(
|
|
265
266
|
.spring(response: 0.5, dampingFraction: 0.78)
|
|
266
|
-
|
|
267
|
+
.delay(Double(index) * 0.07),
|
|
267
268
|
value: appeared)
|
|
268
269
|
}
|
|
269
270
|
}
|
|
@@ -165,15 +165,15 @@ struct AboutPane: View {
|
|
|
165
165
|
|
|
166
166
|
VStack(spacing: RunicSpacing.xxs) {
|
|
167
167
|
Text("Runic")
|
|
168
|
-
.font(.system(size: 26, weight: .bold
|
|
168
|
+
.font(RunicFont.system(size: 26, weight: .bold))
|
|
169
169
|
|
|
170
170
|
Text("Version \(self.versionString)")
|
|
171
|
-
.font(.system(size: 12, weight: .medium
|
|
171
|
+
.font(RunicFont.system(size: 12, weight: .medium))
|
|
172
172
|
.foregroundStyle(.secondary)
|
|
173
173
|
|
|
174
174
|
if let buildTimestamp {
|
|
175
175
|
Text("Built \(buildTimestamp)")
|
|
176
|
-
.font(.system(size: 11
|
|
176
|
+
.font(RunicFont.system(size: 11))
|
|
177
177
|
.foregroundStyle(.tertiary)
|
|
178
178
|
}
|
|
179
179
|
}
|
|
@@ -184,12 +184,12 @@ struct AboutPane: View {
|
|
|
184
184
|
.foregroundStyle(.secondary)
|
|
185
185
|
.multilineTextAlignment(.center)
|
|
186
186
|
Text("From fullness comes fullness.\nWhen fullness is taken from fullness,\nfullness alone remains.")
|
|
187
|
-
.font(.system(size: 11.5, weight: .regular
|
|
187
|
+
.font(RunicFont.system(size: 11.5, weight: .regular))
|
|
188
188
|
.foregroundStyle(.tertiary)
|
|
189
189
|
.multilineTextAlignment(.center)
|
|
190
190
|
.lineSpacing(2)
|
|
191
191
|
Text("— Isha Upanishad")
|
|
192
|
-
.font(.system(size: 10, weight: .medium
|
|
192
|
+
.font(RunicFont.system(size: 10, weight: .medium))
|
|
193
193
|
.foregroundStyle(.quaternary)
|
|
194
194
|
}
|
|
195
195
|
}
|
|
@@ -243,7 +243,7 @@ struct AboutPane: View {
|
|
|
243
243
|
}
|
|
244
244
|
} else {
|
|
245
245
|
Text(self.updater.unavailableReason ?? "Updates unavailable in this build.")
|
|
246
|
-
.font(.system(size: 12
|
|
246
|
+
.font(RunicFont.system(size: 12))
|
|
247
247
|
.foregroundStyle(.secondary)
|
|
248
248
|
.frame(maxWidth: .infinity)
|
|
249
249
|
}
|
|
@@ -257,7 +257,7 @@ struct AboutPane: View {
|
|
|
257
257
|
|
|
258
258
|
private var footerSection: some View {
|
|
259
259
|
Text("© 2025–2026 Srinivas Pendela. MIT License.")
|
|
260
|
-
.font(.system(size: 11
|
|
260
|
+
.font(RunicFont.system(size: 11))
|
|
261
261
|
.foregroundStyle(.tertiary)
|
|
262
262
|
.frame(maxWidth: .infinity)
|
|
263
263
|
.opacity(self.appeared ? 1 : 0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import AppKit
|
|
2
|
-
import RunicCore
|
|
3
2
|
import KeyboardShortcuts
|
|
3
|
+
import RunicCore
|
|
4
4
|
import SwiftUI
|
|
5
5
|
|
|
6
6
|
@MainActor
|
|
@@ -14,7 +14,7 @@ struct AdvancedPane: View {
|
|
|
14
14
|
PreferencesPane {
|
|
15
15
|
SettingsSection(contentSpacing: PreferencesLayoutMetrics.sectionSpacing) {
|
|
16
16
|
Text("Refresh cadence")
|
|
17
|
-
.font(.caption)
|
|
17
|
+
.font(RunicFont.caption)
|
|
18
18
|
.foregroundStyle(.secondary)
|
|
19
19
|
.textCase(.uppercase)
|
|
20
20
|
Picker("", selection: self.$settings.refreshFrequency) {
|
|
@@ -26,12 +26,12 @@ struct AdvancedPane: View {
|
|
|
26
26
|
|
|
27
27
|
if self.settings.refreshFrequency == .manual {
|
|
28
28
|
Text("Auto-refresh is off; use the menu's Refresh command.")
|
|
29
|
-
.font(.footnote)
|
|
29
|
+
.font(RunicFont.footnote)
|
|
30
30
|
.foregroundStyle(.secondary)
|
|
31
31
|
}
|
|
32
32
|
if let badgeText = self.store.autoRefreshDisableBadgeText() {
|
|
33
33
|
Text(badgeText)
|
|
34
|
-
.font(.caption2.weight(.medium))
|
|
34
|
+
.font(RunicFont.caption2.weight(.medium))
|
|
35
35
|
.padding(.horizontal, RunicSpacing.xs)
|
|
36
36
|
.padding(.vertical, RunicSpacing.xxs)
|
|
37
37
|
.background(Color(nsColor: .controlBackgroundColor))
|
|
@@ -39,7 +39,7 @@ struct AdvancedPane: View {
|
|
|
39
39
|
.foregroundStyle(.secondary)
|
|
40
40
|
}
|
|
41
41
|
Text("Auto-refresh can switch to Manual when your Mac is idle or sleeps/locks. Adjust below.")
|
|
42
|
-
.font(.footnote)
|
|
42
|
+
.font(RunicFont.footnote)
|
|
43
43
|
.foregroundStyle(.secondary)
|
|
44
44
|
}
|
|
45
45
|
|
|
@@ -47,19 +47,19 @@ struct AdvancedPane: View {
|
|
|
47
47
|
|
|
48
48
|
SettingsSection(contentSpacing: PreferencesLayoutMetrics.sectionSpacing) {
|
|
49
49
|
Text("Auto-refresh safety")
|
|
50
|
-
.font(.caption)
|
|
50
|
+
.font(RunicFont.caption)
|
|
51
51
|
.foregroundStyle(.secondary)
|
|
52
52
|
.textCase(.uppercase)
|
|
53
53
|
|
|
54
54
|
VStack(alignment: .leading, spacing: RunicSpacing.xs) {
|
|
55
55
|
Toggle(isOn: self.$settings.autoDisableRefreshWhenIdleEnabled) {
|
|
56
56
|
Text("Switch to Manual when idle")
|
|
57
|
-
.font(.body)
|
|
57
|
+
.font(RunicFont.body)
|
|
58
58
|
}
|
|
59
59
|
.toggleStyle(.checkbox)
|
|
60
60
|
|
|
61
61
|
Text("If your Mac is idle for the threshold below, Runic switches auto-refresh to Manual.")
|
|
62
|
-
.font(.footnote)
|
|
62
|
+
.font(RunicFont.footnote)
|
|
63
63
|
.foregroundStyle(.tertiary)
|
|
64
64
|
.fixedSize(horizontal: false, vertical: true)
|
|
65
65
|
|
|
@@ -70,19 +70,19 @@ struct AdvancedPane: View {
|
|
|
70
70
|
range: 1...60,
|
|
71
71
|
valueLabel: { "\($0) min" },
|
|
72
72
|
value: self.$settings.autoDisableRefreshWhenIdleMinutes)
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
.disabled(!self.settings.autoDisableRefreshWhenIdleEnabled)
|
|
74
|
+
.opacity(self.settings.autoDisableRefreshWhenIdleEnabled ? 1 : 0.5)
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
VStack(alignment: .leading, spacing: RunicSpacing.xs) {
|
|
78
78
|
Toggle(isOn: self.$settings.autoDisableRefreshOnSleepEnabled) {
|
|
79
79
|
Text("Switch to Manual on sleep/lock")
|
|
80
|
-
.font(.body)
|
|
80
|
+
.font(RunicFont.body)
|
|
81
81
|
}
|
|
82
82
|
.toggleStyle(.checkbox)
|
|
83
83
|
|
|
84
84
|
Text("When your Mac sleeps or locks, auto-refresh moves to Manual to avoid background checks.")
|
|
85
|
-
.font(.footnote)
|
|
85
|
+
.font(RunicFont.footnote)
|
|
86
86
|
.foregroundStyle(.tertiary)
|
|
87
87
|
.fixedSize(horizontal: false, vertical: true)
|
|
88
88
|
}
|
|
@@ -90,12 +90,12 @@ struct AdvancedPane: View {
|
|
|
90
90
|
VStack(alignment: .leading, spacing: RunicSpacing.xs) {
|
|
91
91
|
Toggle(isOn: self.$settings.autoRefreshWarningEnabled) {
|
|
92
92
|
Text("Warn after repeated auto-refreshes")
|
|
93
|
-
.font(.body)
|
|
93
|
+
.font(RunicFont.body)
|
|
94
94
|
}
|
|
95
95
|
.toggleStyle(.checkbox)
|
|
96
96
|
|
|
97
97
|
Text("Sends a notification after the configured number of auto-refresh cycles.")
|
|
98
|
-
.font(.footnote)
|
|
98
|
+
.font(RunicFont.footnote)
|
|
99
99
|
.foregroundStyle(.tertiary)
|
|
100
100
|
.fixedSize(horizontal: false, vertical: true)
|
|
101
101
|
|
|
@@ -106,19 +106,19 @@ struct AdvancedPane: View {
|
|
|
106
106
|
range: 5...100,
|
|
107
107
|
valueLabel: { "\($0) runs" },
|
|
108
108
|
value: self.$settings.autoRefreshWarningThreshold)
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
.disabled(!self.settings.autoRefreshWarningEnabled)
|
|
110
|
+
.opacity(self.settings.autoRefreshWarningEnabled ? 1 : 0.5)
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
VStack(alignment: .leading, spacing: RunicSpacing.xs) {
|
|
114
114
|
Toggle(isOn: self.$settings.autoSuspendInactiveProvidersEnabled) {
|
|
115
115
|
Text("Skip inactive providers")
|
|
116
|
-
.font(.body)
|
|
116
|
+
.font(RunicFont.body)
|
|
117
117
|
}
|
|
118
118
|
.toggleStyle(.checkbox)
|
|
119
119
|
|
|
120
120
|
Text("Pauses auto-refresh for providers with no usage changes for the threshold below.")
|
|
121
|
-
.font(.footnote)
|
|
121
|
+
.font(RunicFont.footnote)
|
|
122
122
|
.foregroundStyle(.tertiary)
|
|
123
123
|
.fixedSize(horizontal: false, vertical: true)
|
|
124
124
|
|
|
@@ -129,16 +129,16 @@ struct AdvancedPane: View {
|
|
|
129
129
|
range: 30...10080,
|
|
130
130
|
valueLabel: { Self.inactiveThresholdLabel(for: $0) },
|
|
131
131
|
value: self.$settings.autoSuspendInactiveProvidersMinutes)
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
.disabled(!self.settings.autoSuspendInactiveProvidersEnabled)
|
|
133
|
+
.opacity(self.settings.autoSuspendInactiveProvidersEnabled ? 1 : 0.5)
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
Text("Auto-refresh can read local logs or browser cookies depending on provider settings.")
|
|
137
|
-
.font(.footnote)
|
|
137
|
+
.font(RunicFont.footnote)
|
|
138
138
|
.foregroundStyle(.tertiary)
|
|
139
139
|
.fixedSize(horizontal: false, vertical: true)
|
|
140
140
|
Text("Auto-refresh also switches to Manual when your Mac sleeps or is locked.")
|
|
141
|
-
.font(.footnote)
|
|
141
|
+
.font(RunicFont.footnote)
|
|
142
142
|
.foregroundStyle(.tertiary)
|
|
143
143
|
.fixedSize(horizontal: false, vertical: true)
|
|
144
144
|
}
|
|
@@ -147,17 +147,17 @@ struct AdvancedPane: View {
|
|
|
147
147
|
|
|
148
148
|
SettingsSection(contentSpacing: PreferencesLayoutMetrics.sectionSpacing) {
|
|
149
149
|
Text("Keyboard shortcut")
|
|
150
|
-
.font(.caption)
|
|
150
|
+
.font(RunicFont.caption)
|
|
151
151
|
.foregroundStyle(.secondary)
|
|
152
152
|
.textCase(.uppercase)
|
|
153
153
|
HStack(alignment: .center, spacing: RunicSpacing.sm) {
|
|
154
154
|
Text("Open menu")
|
|
155
|
-
.font(.body)
|
|
155
|
+
.font(RunicFont.body)
|
|
156
156
|
Spacer()
|
|
157
157
|
KeyboardShortcuts.Recorder(for: .openMenu)
|
|
158
158
|
}
|
|
159
159
|
Text("Trigger the menu bar menu from anywhere.")
|
|
160
|
-
.font(.footnote)
|
|
160
|
+
.font(RunicFont.footnote)
|
|
161
161
|
.foregroundStyle(.tertiary)
|
|
162
162
|
}
|
|
163
163
|
|
|
@@ -178,13 +178,13 @@ struct AdvancedPane: View {
|
|
|
178
178
|
|
|
179
179
|
if let status = self.cliStatus {
|
|
180
180
|
Text(status)
|
|
181
|
-
.font(.footnote)
|
|
181
|
+
.font(RunicFont.footnote)
|
|
182
182
|
.foregroundStyle(.tertiary)
|
|
183
183
|
.lineLimit(2)
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
Text("Symlink RunicCLI to /usr/local/bin and /opt/homebrew/bin as runic.")
|
|
187
|
-
.font(.footnote)
|
|
187
|
+
.font(RunicFont.footnote)
|
|
188
188
|
.foregroundStyle(.tertiary)
|
|
189
189
|
}
|
|
190
190
|
|