@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.
Files changed (342) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +8 -1
  3. package/RuniciOS/Core/RunicTypographyiOS.swift +24 -0
  4. package/RuniciOS/Views/ProviderDetailView.swift +9 -9
  5. package/RuniciOS/Views/ProviderListView.swift +10 -10
  6. package/RuniciOS/Widgets/LargeWidget.swift +14 -14
  7. package/RuniciOS/Widgets/LiveActivity.swift +19 -19
  8. package/RuniciOS/Widgets/LockScreenWidget.swift +15 -15
  9. package/RuniciOS/Widgets/MediumWidget.swift +10 -10
  10. package/RuniciOS/Widgets/RunicWidget.swift +5 -5
  11. package/RuniciOS/Widgets/SmallWidget.swift +9 -9
  12. package/Sources/Runic/About.swift +3 -3
  13. package/Sources/Runic/AppNotifications.swift +5 -3
  14. package/Sources/Runic/Controllers/StatusItemController+Actions.swift +7 -3
  15. package/Sources/Runic/Controllers/StatusItemController+Animation.swift +5 -4
  16. package/Sources/Runic/Controllers/StatusItemController+ChartSubmenus.swift +30 -16
  17. package/Sources/Runic/Controllers/StatusItemController+CustomProviders.swift +6 -3
  18. package/Sources/Runic/Controllers/StatusItemController+Menu.swift +18 -13
  19. package/Sources/Runic/Controllers/StatusItemController+MenuCards.swift +6 -4
  20. package/Sources/Runic/Controllers/StatusItemController+MenuHelpers.swift +40 -12
  21. package/Sources/Runic/Controllers/StatusItemController.swift +43 -43
  22. package/Sources/Runic/Core/BudgetNotificationManager.swift +2 -1
  23. package/Sources/Runic/Core/Login/ClaudeLoginRunner.swift +2 -2
  24. package/Sources/Runic/Core/Login/CodexLoginRunner.swift +1 -1
  25. package/Sources/Runic/Core/Login/CursorLoginRunner.swift +4 -4
  26. package/Sources/Runic/Core/Login/GeminiLoginRunner.swift +1 -1
  27. package/Sources/Runic/Core/Rendering/IconRenderer.swift +91 -85
  28. package/Sources/Runic/Core/Rendering/IconView.swift +3 -1
  29. package/Sources/Runic/Core/RunicColors.swift +6 -6
  30. package/Sources/Runic/Core/RunicSpacing.swift +7 -7
  31. package/Sources/Runic/Core/RunicTypography.swift +206 -0
  32. package/Sources/Runic/Core/Stores/AuggieTokenStore.swift +1 -3
  33. package/Sources/Runic/Core/Stores/AzureOpenAITokenStore.swift +1 -3
  34. package/Sources/Runic/Core/Stores/CerebrasTokenStore.swift +1 -3
  35. package/Sources/Runic/Core/Stores/CohereTokenStore.swift +1 -3
  36. package/Sources/Runic/Core/Stores/CopilotTokenStore.swift +1 -3
  37. package/Sources/Runic/Core/Stores/CustomProviderStore.swift +10 -10
  38. package/Sources/Runic/Core/Stores/DeepSeekTokenStore.swift +1 -3
  39. package/Sources/Runic/Core/Stores/FireworksTokenStore.swift +1 -3
  40. package/Sources/Runic/Core/Stores/GroqTokenStore.swift +1 -3
  41. package/Sources/Runic/Core/Stores/KimiTokenStore.swift +1 -3
  42. package/Sources/Runic/Core/Stores/MiniMaxCookieHeaderStore.swift +1 -3
  43. package/Sources/Runic/Core/Stores/MiniMaxGroupIDStore.swift +1 -3
  44. package/Sources/Runic/Core/Stores/MiniMaxTokenStore.swift +1 -3
  45. package/Sources/Runic/Core/Stores/MistralTokenStore.swift +1 -3
  46. package/Sources/Runic/Core/Stores/OpenRouterTokenStore.swift +1 -3
  47. package/Sources/Runic/Core/Stores/PerplexityTokenStore.swift +1 -3
  48. package/Sources/Runic/Core/Stores/ProviderToggleStore.swift +1 -1
  49. package/Sources/Runic/Core/Stores/QwenTokenStore.swift +1 -3
  50. package/Sources/Runic/Core/Stores/SambaNovaTokenStore.swift +1 -3
  51. package/Sources/Runic/Core/Stores/SettingsStore.swift +89 -51
  52. package/Sources/Runic/Core/Stores/TogetherTokenStore.swift +1 -3
  53. package/Sources/Runic/Core/Stores/UsageStore+Accessors.swift +19 -6
  54. package/Sources/Runic/Core/Stores/UsageStore+TokenCost.swift +1 -1
  55. package/Sources/Runic/Core/Stores/UsageStore+WidgetSnapshot.swift +1 -1
  56. package/Sources/Runic/Core/Stores/UsageStore.swift +187 -161
  57. package/Sources/Runic/Core/Stores/XAITokenStore.swift +1 -3
  58. package/Sources/Runic/Core/Stores/ZaiTokenStore.swift +1 -2
  59. package/Sources/Runic/Core/UsageExporter.swift +8 -4
  60. package/Sources/Runic/ProviderRegistry.swift +1 -1
  61. package/Sources/Runic/Providers/Antigravity/AntigravityProviderImplementation.swift +1 -1
  62. package/Sources/Runic/Providers/Auggie/AuggieProviderImplementation.swift +1 -1
  63. package/Sources/Runic/Providers/Azure/AzureProviderImplementation.swift +1 -1
  64. package/Sources/Runic/Providers/Bedrock/BedrockProviderImplementation.swift +1 -1
  65. package/Sources/Runic/Providers/Cerebras/CerebrasProviderImplementation.swift +1 -1
  66. package/Sources/Runic/Providers/Codex/CodexProviderImplementation.swift +1 -1
  67. package/Sources/Runic/Providers/Cohere/CohereProviderImplementation.swift +1 -1
  68. package/Sources/Runic/Providers/Cursor/CursorProviderImplementation.swift +1 -1
  69. package/Sources/Runic/Providers/DeepSeek/DeepSeekProviderImplementation.swift +1 -1
  70. package/Sources/Runic/Providers/Factory/FactoryProviderImplementation.swift +1 -1
  71. package/Sources/Runic/Providers/Fireworks/FireworksProviderImplementation.swift +1 -1
  72. package/Sources/Runic/Providers/Gemini/GeminiProviderImplementation.swift +1 -1
  73. package/Sources/Runic/Providers/Groq/GroqProviderImplementation.swift +1 -1
  74. package/Sources/Runic/Providers/Kimi/KimiProviderImplementation.swift +1 -1
  75. package/Sources/Runic/Providers/MiniMax/MiniMaxProviderImplementation.swift +1 -1
  76. package/Sources/Runic/Providers/Mistral/MistralProviderImplementation.swift +1 -1
  77. package/Sources/Runic/Providers/OpenRouter/OpenRouterProviderImplementation.swift +1 -1
  78. package/Sources/Runic/Providers/Perplexity/PerplexityProviderImplementation.swift +1 -1
  79. package/Sources/Runic/Providers/SambaNova/SambaNovaProviderImplementation.swift +1 -1
  80. package/Sources/Runic/Providers/Shared/ProviderImplementation.swift +5 -2
  81. package/Sources/Runic/Providers/Shared/ProviderImplementationRegistry.swift +1 -1
  82. package/Sources/Runic/Providers/Shared/ProviderSettingsDescriptors.swift +1 -1
  83. package/Sources/Runic/Providers/Together/TogetherProviderImplementation.swift +1 -1
  84. package/Sources/Runic/Providers/XAI/XAIProviderImplementation.swift +1 -1
  85. package/Sources/Runic/Providers/Zai/ZaiProviderImplementation.swift +1 -1
  86. package/Sources/Runic/Resources/Fonts/Caveat-Bold.ttf +0 -0
  87. package/Sources/Runic/Resources/Fonts/Caveat-Regular.ttf +0 -0
  88. package/Sources/Runic/Resources/Fonts/FiraCode-Bold.ttf +0 -0
  89. package/Sources/Runic/Resources/Fonts/FiraCode-Light.ttf +0 -0
  90. package/Sources/Runic/Resources/Fonts/FiraCode-Medium.ttf +0 -0
  91. package/Sources/Runic/Resources/Fonts/FiraCode-Regular.ttf +0 -0
  92. package/Sources/Runic/Resources/Fonts/FiraCode-SemiBold.ttf +0 -0
  93. package/Sources/Runic/Resources/Fonts/IBMPlexMono-Bold.ttf +0 -0
  94. package/Sources/Runic/Resources/Fonts/IBMPlexMono-Medium.ttf +0 -0
  95. package/Sources/Runic/Resources/Fonts/IBMPlexMono-Regular.ttf +0 -0
  96. package/Sources/Runic/Resources/Fonts/IBMPlexMono-SemiBold.ttf +0 -0
  97. package/Sources/Runic/Resources/Fonts/Inconsolata-Bold.ttf +0 -0
  98. package/Sources/Runic/Resources/Fonts/Inconsolata-Medium.ttf +0 -0
  99. package/Sources/Runic/Resources/Fonts/Inconsolata-Regular.ttf +0 -0
  100. package/Sources/Runic/Resources/Fonts/Inconsolata-SemiBold.ttf +0 -0
  101. package/Sources/Runic/Resources/Fonts/JetBrainsMono-Bold.ttf +0 -0
  102. package/Sources/Runic/Resources/Fonts/JetBrainsMono-Medium.ttf +0 -0
  103. package/Sources/Runic/Resources/Fonts/JetBrainsMono-Regular.ttf +0 -0
  104. package/Sources/Runic/Resources/Fonts/JetBrainsMono-SemiBold.ttf +0 -0
  105. package/Sources/Runic/Resources/Fonts/SpaceMono-Bold.ttf +0 -0
  106. package/Sources/Runic/Resources/Fonts/SpaceMono-Regular.ttf +0 -0
  107. package/Sources/Runic/RunicApp.swift +46 -36
  108. package/Sources/Runic/SessionQuotaNotifications.swift +2 -2
  109. package/Sources/Runic/UsagePaceText.swift +1 -1
  110. package/Sources/Runic/UsageProgressBar.swift +13 -9
  111. package/Sources/Runic/Utilities/LoadingPattern.swift +4 -2
  112. package/Sources/Runic/Utilities/PerformanceConstants.swift +28 -28
  113. package/Sources/Runic/Views/Menu/AlertsMenuView.swift +19 -21
  114. package/Sources/Runic/Views/Menu/CostComparativeChartMenuView.swift +19 -19
  115. package/Sources/Runic/Views/Menu/CostHistoryChartMenuView.swift +7 -7
  116. package/Sources/Runic/Views/Menu/CreditsHistoryChartMenuView.swift +5 -5
  117. package/Sources/Runic/Views/Menu/EfficiencyMetricsMenuView.swift +29 -30
  118. package/Sources/Runic/Views/Menu/HeroStatCardsMenuView.swift +20 -17
  119. package/Sources/Runic/Views/Menu/HourlyActivityChartMenuView.swift +14 -14
  120. package/Sources/Runic/Views/Menu/InlineUsageChartView.swift +12 -10
  121. package/Sources/Runic/Views/Menu/MenuCardEntranceModifier.swift +3 -4
  122. package/Sources/Runic/Views/Menu/MenuCardSidebarView.swift +5 -25
  123. package/Sources/Runic/Views/Menu/MenuCardSkeletonView.swift +1 -1
  124. package/Sources/Runic/Views/Menu/MenuCardView.swift +120 -131
  125. package/Sources/Runic/Views/Menu/MenuContent.swift +11 -8
  126. package/Sources/Runic/Views/Menu/MenuDescriptor.swift +4 -2
  127. package/Sources/Runic/Views/Menu/MenuHighlightStyle.swift +1 -8
  128. package/Sources/Runic/Views/Menu/ModelBreakdownMenuView.swift +20 -14
  129. package/Sources/Runic/Views/Menu/OverviewMenuView.swift +18 -15
  130. package/Sources/Runic/Views/Menu/ProjectBreakdownMenuView.swift +16 -11
  131. package/Sources/Runic/Views/Menu/ProjectBudgetMenuView.swift +27 -27
  132. package/Sources/Runic/Views/Menu/ProviderTabBarView.swift +4 -6
  133. package/Sources/Runic/Views/Menu/SubscriptionUtilizationChartMenuView.swift +24 -11
  134. package/Sources/Runic/Views/Menu/UsageBreakdownChartMenuView.swift +5 -5
  135. package/Sources/Runic/Views/Menu/UsageHeatmapMenuView.swift +7 -8
  136. package/Sources/Runic/Views/Menu/UsageTimelineChartMenuView.swift +22 -17
  137. package/Sources/Runic/Views/Menu/UsageWindowComparisonChartMenuView.swift +8 -7
  138. package/Sources/Runic/Views/Menu/WeeklyActivityChartMenuView.swift +7 -7
  139. package/Sources/Runic/Views/Performance/PerformanceDashboardView.swift +50 -47
  140. package/Sources/Runic/Views/Preferences/LiquidComponents.swift +15 -14
  141. package/Sources/Runic/Views/Preferences/PreferencesAboutPane.swift +7 -7
  142. package/Sources/Runic/Views/Preferences/PreferencesAdvancedPane.swift +27 -27
  143. package/Sources/Runic/Views/Preferences/PreferencesAlertsPane.swift +38 -42
  144. package/Sources/Runic/Views/Preferences/PreferencesAnalyticsPane.swift +39 -43
  145. package/Sources/Runic/Views/Preferences/PreferencesBudgetsPane.swift +21 -21
  146. package/Sources/Runic/Views/Preferences/PreferencesComponents.swift +7 -7
  147. package/Sources/Runic/Views/Preferences/PreferencesCustomProvidersPane.swift +49 -50
  148. package/Sources/Runic/Views/Preferences/PreferencesDebugPane.swift +10 -10
  149. package/Sources/Runic/Views/Preferences/PreferencesGeneralPane.swift +40 -21
  150. package/Sources/Runic/Views/Preferences/PreferencesHelpPane.swift +7 -7
  151. package/Sources/Runic/Views/Preferences/PreferencesIntegrationsPane.swift +44 -39
  152. package/Sources/Runic/Views/Preferences/PreferencesPerformancePane.swift +26 -23
  153. package/Sources/Runic/Views/Preferences/PreferencesProvidersPane.swift +271 -226
  154. package/Sources/Runic/Views/Preferences/PreferencesSelection.swift +6 -2
  155. package/Sources/Runic/Views/Preferences/PreferencesSyncPane.swift +7 -5
  156. package/Sources/Runic/Views/Preferences/PreferencesView.swift +38 -31
  157. package/Sources/Runic/Views/Rating/QualityRatingView.swift +11 -11
  158. package/Sources/Runic/Views/Team/TeamDashboardView.swift +29 -24
  159. package/Sources/Runic/Views/Team/TeamInviteSheet.swift +16 -16
  160. package/Sources/Runic/Views/Team/TeamManagementView.swift +50 -49
  161. package/Sources/Runic/Views/Team/TeamMemberRow.swift +8 -8
  162. package/Sources/RunicCLI/CLIEntry.swift +83 -42
  163. package/Sources/RunicCLI/CLIRenderer.swift +1 -1
  164. package/Sources/RunicCLI/Commands/EnhancedUsageCommand.swift +60 -60
  165. package/Sources/RunicCLI/Commands/ModelsCommand.swift +45 -44
  166. package/Sources/RunicCLI/Commands/ProjectsCommand.swift +83 -69
  167. package/Sources/RunicCLI/Commands/ResetCommand.swift +50 -49
  168. package/Sources/RunicCLI/Commands/UsageLedgerSourceFactory.swift +31 -32
  169. package/Sources/RunicClaudeWebProbe/main.swift +1 -1
  170. package/Sources/RunicCore/AlertRuleStore.swift +20 -20
  171. package/Sources/RunicCore/BrowserCookieImportOrder.swift +3 -3
  172. package/Sources/RunicCore/CostUsageModels.swift +1 -1
  173. package/Sources/RunicCore/CustomProviders/CustomProviderModels.swift +29 -30
  174. package/Sources/RunicCore/CustomProviders/GenericProviderFetcher.swift +73 -75
  175. package/Sources/RunicCore/CustomProviders/ProviderTemplates.swift +53 -109
  176. package/Sources/RunicCore/Host/PTY/TTYCommandRunner.swift +3 -3
  177. package/Sources/RunicCore/Integrations/GitHubIntegration.swift +3 -3
  178. package/Sources/RunicCore/Models/EnhancedUsageModels.swift +47 -48
  179. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardBrowserCookieImporter.swift +1 -1
  180. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardFetcher.swift +1 -1
  181. package/Sources/RunicCore/Performance/PerformanceModels.swift +4 -4
  182. package/Sources/RunicCore/Performance/PerformanceStorageImpl.swift +81 -64
  183. package/Sources/RunicCore/Policy/UsagePolicyEngine.swift +2 -2
  184. package/Sources/RunicCore/ProjectBudgetStore.swift +15 -12
  185. package/Sources/RunicCore/Providers/Antigravity/AntigravityProviderDescriptor.swift +4 -2
  186. package/Sources/RunicCore/Providers/Antigravity/AntigravityStatusProbe.swift +2 -2
  187. package/Sources/RunicCore/Providers/Auggie/AuggieProviderDescriptor.swift +2 -2
  188. package/Sources/RunicCore/Providers/Auggie/AuggieUsageFetcher.swift +3 -3
  189. package/Sources/RunicCore/Providers/Azure/AzureProviderDescriptor.swift +8 -8
  190. package/Sources/RunicCore/Providers/Azure/AzureUsageFetcher.swift +3 -3
  191. package/Sources/RunicCore/Providers/Bedrock/BedrockProviderDescriptor.swift +6 -6
  192. package/Sources/RunicCore/Providers/Bedrock/BedrockUsageFetcher.swift +3 -7
  193. package/Sources/RunicCore/Providers/Cerebras/CerebrasProviderDescriptor.swift +2 -2
  194. package/Sources/RunicCore/Providers/Cerebras/CerebrasUsageFetcher.swift +2 -2
  195. package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthUsageFetcher.swift +3 -3
  196. package/Sources/RunicCore/Providers/Claude/ClaudeProviderDescriptor.swift +4 -2
  197. package/Sources/RunicCore/Providers/Claude/ClaudeStatusProbe.swift +4 -4
  198. package/Sources/RunicCore/Providers/Claude/ClaudeUsageDataSource.swift +3 -1
  199. package/Sources/RunicCore/Providers/Claude/ClaudeWeb/ClaudeWebAPIFetcher.swift +1 -1
  200. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthUsageFetcher.swift +1 -1
  201. package/Sources/RunicCore/Providers/Codex/CodexProviderDescriptor.swift +4 -2
  202. package/Sources/RunicCore/Providers/Codex/CodexUsageDataSource.swift +3 -1
  203. package/Sources/RunicCore/Providers/Codex/CodexWebDashboardStrategy.swift +5 -3
  204. package/Sources/RunicCore/Providers/Cohere/CohereProviderDescriptor.swift +2 -2
  205. package/Sources/RunicCore/Providers/Cohere/CohereUsageFetcher.swift +3 -3
  206. package/Sources/RunicCore/Providers/Copilot/CopilotGitHubCLITokenReader.swift +7 -4
  207. package/Sources/RunicCore/Providers/Copilot/CopilotProviderDescriptor.swift +4 -4
  208. package/Sources/RunicCore/Providers/Copilot/CopilotUsageFetcher.swift +5 -3
  209. package/Sources/RunicCore/Providers/Copilot/CopilotVSCodeTokenReader.swift +9 -10
  210. package/Sources/RunicCore/Providers/Cursor/CursorProviderDescriptor.swift +4 -2
  211. package/Sources/RunicCore/Providers/DeepSeek/DeepSeekProviderDescriptor.swift +2 -2
  212. package/Sources/RunicCore/Providers/DeepSeek/DeepSeekUsageFetcher.swift +2 -2
  213. package/Sources/RunicCore/Providers/Factory/FactoryLocalStorageImporter.swift +4 -4
  214. package/Sources/RunicCore/Providers/Factory/FactoryProviderDescriptor.swift +4 -2
  215. package/Sources/RunicCore/Providers/Factory/FactoryStatusProbe.swift +2 -2
  216. package/Sources/RunicCore/Providers/Fireworks/FireworksProviderDescriptor.swift +2 -2
  217. package/Sources/RunicCore/Providers/Fireworks/FireworksUsageFetcher.swift +2 -2
  218. package/Sources/RunicCore/Providers/Gemini/GeminiProviderDescriptor.swift +4 -2
  219. package/Sources/RunicCore/Providers/Gemini/GeminiStatusProbe.swift +5 -2
  220. package/Sources/RunicCore/Providers/Groq/GroqProviderDescriptor.swift +2 -2
  221. package/Sources/RunicCore/Providers/Groq/GroqUsageFetcher.swift +2 -2
  222. package/Sources/RunicCore/Providers/Kimi/KimiProviderDescriptor.swift +2 -2
  223. package/Sources/RunicCore/Providers/Kimi/KimiUsageFetcher.swift +2 -2
  224. package/Sources/RunicCore/Providers/MiniMax/MiniMaxProviderDescriptor.swift +10 -5
  225. package/Sources/RunicCore/Providers/MiniMax/MiniMaxUsageFetcher.swift +7 -7
  226. package/Sources/RunicCore/Providers/MiniMax/MiniMaxWebUsageFetcher.swift +10 -10
  227. package/Sources/RunicCore/Providers/Mistral/MistralProviderDescriptor.swift +2 -2
  228. package/Sources/RunicCore/Providers/Mistral/MistralUsageFetcher.swift +2 -2
  229. package/Sources/RunicCore/Providers/OpenRouter/OpenRouterProviderDescriptor.swift +2 -2
  230. package/Sources/RunicCore/Providers/OpenRouter/OpenRouterUsageFetcher.swift +23 -10
  231. package/Sources/RunicCore/Providers/Perplexity/PerplexityProviderDescriptor.swift +2 -2
  232. package/Sources/RunicCore/Providers/Perplexity/PerplexityUsageFetcher.swift +2 -2
  233. package/Sources/RunicCore/Providers/ProviderFetchPlan.swift +2 -2
  234. package/Sources/RunicCore/Providers/ProviderTokenResolver.swift +2 -2
  235. package/Sources/RunicCore/Providers/Qwen/QwenProviderDescriptor.swift +5 -3
  236. package/Sources/RunicCore/Providers/Qwen/QwenUsageStats.swift +26 -13
  237. package/Sources/RunicCore/Providers/SambaNova/SambaNovaProviderDescriptor.swift +2 -2
  238. package/Sources/RunicCore/Providers/SambaNova/SambaNovaUsageFetcher.swift +2 -2
  239. package/Sources/RunicCore/Providers/Together/TogetherProviderDescriptor.swift +2 -2
  240. package/Sources/RunicCore/Providers/Together/TogetherUsageFetcher.swift +2 -2
  241. package/Sources/RunicCore/Providers/VertexAI/VertexAIProviderDescriptor.swift +5 -5
  242. package/Sources/RunicCore/Providers/VertexAI/VertexAISettingsReader.swift +1 -1
  243. package/Sources/RunicCore/Providers/VertexAI/VertexAIUsageFetcher.swift +3 -3
  244. package/Sources/RunicCore/Providers/XAI/XAIProviderDescriptor.swift +2 -2
  245. package/Sources/RunicCore/Providers/XAI/XAIUsageFetcher.swift +2 -2
  246. package/Sources/RunicCore/Providers/Zai/ZaiProviderDescriptor.swift +4 -2
  247. package/Sources/RunicCore/Providers/Zai/ZaiUsageStats.swift +48 -21
  248. package/Sources/RunicCore/Sync/BackgroundSyncManager.swift +76 -77
  249. package/Sources/RunicCore/Sync/SyncConflictResolver.swift +55 -58
  250. package/Sources/RunicCore/Sync/SyncProtocol.swift +21 -22
  251. package/Sources/RunicCore/Sync/SyncRecord.swift +46 -49
  252. package/Sources/RunicCore/Sync/SyncUsageExample.swift +44 -50
  253. package/Sources/RunicCore/Sync/TeamSyncRecords.swift +94 -101
  254. package/Sources/RunicCore/Sync/iCloudSyncEngine.swift +51 -46
  255. package/Sources/RunicCore/Team/TeamModels.swift +111 -110
  256. package/Sources/RunicCore/Team/TeamStore.swift +126 -109
  257. package/Sources/RunicCore/UsageFetcher.swift +2 -2
  258. package/Sources/RunicCore/UsageFormatter.swift +25 -25
  259. package/Sources/RunicCore/UsageLedger/ClaudeUsageLogSource.swift +27 -13
  260. package/Sources/RunicCore/UsageLedger/CodexUsageLogSource.swift +11 -3
  261. package/Sources/RunicCore/UsageLedger/LedgerCache.swift +5 -2
  262. package/Sources/RunicCore/UsageLedger/OTelGenAILedgerAdapter.swift +1 -1
  263. package/Sources/RunicCore/UsageLedger/UsageLedgerAggregator.swift +40 -25
  264. package/Sources/RunicCore/UsageLedger/UsageLedgerInsightsAdvisor.swift +1 -1
  265. package/Sources/RunicCore/UsageLedger/UsageLedgerProjectIdentity.swift +55 -16
  266. package/Sources/RunicCore/Vendored/CostUsage/CostUsageCache.swift +6 -6
  267. package/Sources/RunicCore/Vendored/CostUsage/CostUsageJsonl.swift +1 -1
  268. package/Sources/RunicCore/Vendored/CostUsage/CostUsagePricing.swift +2 -2
  269. package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner.swift +5 -5
  270. package/Tests/RunicTests/AppDelegateTests.swift +8 -3
  271. package/Tests/RunicTests/BrowserCookieOrderLabelTests.swift +2 -3
  272. package/Tests/RunicTests/CLIArgumentParsingTests.swift +3 -4
  273. package/Tests/RunicTests/CLICostTests.swift +6 -7
  274. package/Tests/RunicTests/CLIProviderSelectionTests.swift +2 -3
  275. package/Tests/RunicTests/CLISnapshotTests.swift +3 -4
  276. package/Tests/RunicTests/CLIWebFallbackTests.swift +3 -4
  277. package/Tests/RunicTests/ClaudeOAuthTests.swift +11 -12
  278. package/Tests/RunicTests/ClaudeResilienceTests.swift +3 -4
  279. package/Tests/RunicTests/ClaudeUsageTests.swift +20 -21
  280. package/Tests/RunicTests/CodexOAuthTests.swift +7 -8
  281. package/Tests/RunicTests/CodexUsageLogSourceTests.swift +1 -3
  282. package/Tests/RunicTests/CopilotTokenResolverTests.swift +5 -6
  283. package/Tests/RunicTests/CopilotVSCodeTokenReaderTests.swift +4 -5
  284. package/Tests/RunicTests/CostUsageDecodingTests.swift +15 -17
  285. package/Tests/RunicTests/CostUsagePricingTests.swift +5 -7
  286. package/Tests/RunicTests/CostUsageScannerTests.swift +10 -12
  287. package/Tests/RunicTests/CursorStatusProbeTests.swift +15 -16
  288. package/Tests/RunicTests/FactoryStatusProbeTests.swift +3 -5
  289. package/Tests/RunicTests/GeminiLoginAlertTests.swift +3 -4
  290. package/Tests/RunicTests/GeminiStatusProbeAPITests.swift +11 -11
  291. package/Tests/RunicTests/GeminiStatusProbePlanTests.swift +8 -8
  292. package/Tests/RunicTests/GeminiStatusProbeTests.swift +20 -21
  293. package/Tests/RunicTests/GoogleWorkspaceStatusTests.swift +2 -3
  294. package/Tests/RunicTests/InstallOriginTests.swift +1 -2
  295. package/Tests/RunicTests/KeyboardShortcutsBundleTests.swift +2 -2
  296. package/Tests/RunicTests/LiveAccountTests.swift +3 -3
  297. package/Tests/RunicTests/LoadingPatternTests.swift +3 -4
  298. package/Tests/RunicTests/MenuCardModelTests.swift +33 -34
  299. package/Tests/RunicTests/MiniMaxCookieHeaderStoreTestSupport.swift +4 -1
  300. package/Tests/RunicTests/MiniMaxGroupIDStoreTestSupport.swift +4 -1
  301. package/Tests/RunicTests/MiniMaxParsingTests.swift +4 -5
  302. package/Tests/RunicTests/MiniMaxTokenStoreTestSupport.swift +4 -1
  303. package/Tests/RunicTests/OTelGenAILedgerAdapterTests.swift +4 -6
  304. package/Tests/RunicTests/OpenAIDashboardBrowserCookieImporterTests.swift +1 -2
  305. package/Tests/RunicTests/OpenAIDashboardFetcherCreditsWaitTests.swift +5 -6
  306. package/Tests/RunicTests/OpenAIDashboardOffscreenHostTests.swift +2 -3
  307. package/Tests/RunicTests/OpenAIDashboardParserTests.swift +12 -13
  308. package/Tests/RunicTests/OpenAIWebAccountSwitchTests.swift +17 -6
  309. package/Tests/RunicTests/OpenRouterTokenStoreTestSupport.swift +52 -13
  310. package/Tests/RunicTests/PathBuilderTests.swift +14 -15
  311. package/Tests/RunicTests/ProviderFetchPipelineTests.swift +3 -4
  312. package/Tests/RunicTests/ProviderIconResourcesTests.swift +1 -2
  313. package/Tests/RunicTests/ProviderMetadataStatusLinkTests.swift +1 -2
  314. package/Tests/RunicTests/ProviderSettingsDescriptorTests.swift +53 -19
  315. package/Tests/RunicTests/ProviderToggleStoreTests.swift +10 -11
  316. package/Tests/RunicTests/RunicTests.swift +6 -7
  317. package/Tests/RunicTests/SessionQuotaNotificationLogicTests.swift +5 -6
  318. package/Tests/RunicTests/SettingsStoreTests.swift +149 -45
  319. package/Tests/RunicTests/StatusItemAnimationTests.swift +8 -3
  320. package/Tests/RunicTests/StatusMenuTests.swift +63 -22
  321. package/Tests/RunicTests/StatusProbeTests.swift +28 -29
  322. package/Tests/RunicTests/SubprocessRunnerTests.swift +1 -3
  323. package/Tests/RunicTests/SubscriptionDetectionTests.swift +8 -9
  324. package/Tests/RunicTests/TTYCommandRunnerTests.swift +8 -9
  325. package/Tests/RunicTests/TeamShowbackExporterTests.swift +2 -4
  326. package/Tests/RunicTests/TextParsingTests.swift +1 -2
  327. package/Tests/RunicTests/UsageFormatterTests.swift +15 -16
  328. package/Tests/RunicTests/UsageLedgerAnomalyDetectionTests.swift +12 -14
  329. package/Tests/RunicTests/UsageLedgerForecastTests.swift +4 -6
  330. package/Tests/RunicTests/UsageLedgerInsightsAdvisorTests.swift +7 -9
  331. package/Tests/RunicTests/UsageLedgerProjectNameTests.swift +6 -8
  332. package/Tests/RunicTests/UsagePaceTests.swift +5 -6
  333. package/Tests/RunicTests/UsagePaceTextTests.swift +8 -9
  334. package/Tests/RunicTests/UsagePolicyEngineTests.swift +3 -5
  335. package/Tests/RunicTests/WidgetSnapshotTests.swift +1 -3
  336. package/Tests/RunicTests/ZaiProviderTests.swift +3 -5
  337. package/Tests/RunicTests/ZaiTokenStoreTestSupport.swift +4 -1
  338. package/appcast.xml +36 -76
  339. package/package.json +1 -1
  340. package/runic.png +0 -0
  341. package/runic.svg +15 -0
  342. 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 { self.rawValue }
15
+ var id: String {
16
+ self.rawValue
17
+ }
17
18
 
18
- var displayName: String { self.rawValue }
19
+ var displayName: String {
20
+ self.rawValue
21
+ }
19
22
 
20
23
  var days: Int {
21
24
  switch self {
22
- case .day24h: return 1
23
- case .days7: return 7
24
- case .days30: return 30
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 { $0.model }.filter { !$0.isEmpty }
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: return aggregated.rating1Count
405
- case 2: return aggregated.rating2Count
406
- case 3: return aggregated.rating3Count
407
- case 4: return aggregated.rating4Count
408
- case 5: return aggregated.rating5Count
409
- default: return 0
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: [.clear, Color.primary.opacity(0.04), Color.primary.opacity(0.07), Color.primary.opacity(0.04), .clear],
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
- .repeatForever(autoreverses: false)
103
- .delay(self.stableDelay))
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 && !self.reduceMotion {
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(let pt):
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(.system(.caption, design: .rounded).weight(.semibold))
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
- .delay(Double(index) * 0.07),
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, design: .rounded))
168
+ .font(RunicFont.system(size: 26, weight: .bold))
169
169
 
170
170
  Text("Version \(self.versionString)")
171
- .font(.system(size: 12, weight: .medium, design: .rounded))
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, design: .rounded))
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, design: .rounded))
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, design: .rounded))
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, design: .rounded))
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, design: .rounded))
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
- .disabled(!self.settings.autoDisableRefreshWhenIdleEnabled)
74
- .opacity(self.settings.autoDisableRefreshWhenIdleEnabled ? 1 : 0.5)
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
- .disabled(!self.settings.autoRefreshWarningEnabled)
110
- .opacity(self.settings.autoRefreshWarningEnabled ? 1 : 0.5)
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
- .disabled(!self.settings.autoSuspendInactiveProvidersEnabled)
133
- .opacity(self.settings.autoSuspendInactiveProvidersEnabled ? 1 : 0.5)
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