@sriinnu/runic 1.0.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 (348) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +1 -1
  3. package/README.md +47 -29
  4. package/RuniciOS/Core/RunicTypographyiOS.swift +24 -0
  5. package/RuniciOS/Views/ProviderDetailView.swift +9 -9
  6. package/RuniciOS/Views/ProviderListView.swift +10 -10
  7. package/RuniciOS/Widgets/LargeWidget.swift +14 -14
  8. package/RuniciOS/Widgets/LiveActivity.swift +19 -19
  9. package/RuniciOS/Widgets/LockScreenWidget.swift +15 -15
  10. package/RuniciOS/Widgets/MediumWidget.swift +10 -10
  11. package/RuniciOS/Widgets/RunicWidget.swift +5 -5
  12. package/RuniciOS/Widgets/SmallWidget.swift +9 -9
  13. package/Scripts/package_app.sh +2 -2
  14. package/Sources/Runic/About.swift +3 -3
  15. package/Sources/Runic/AppNotifications.swift +5 -3
  16. package/Sources/Runic/Controllers/StatusItemController+Actions.swift +17 -4
  17. package/Sources/Runic/Controllers/StatusItemController+Animation.swift +5 -4
  18. package/Sources/Runic/Controllers/StatusItemController+ChartSubmenus.swift +30 -16
  19. package/Sources/Runic/Controllers/StatusItemController+CustomProviders.swift +6 -3
  20. package/Sources/Runic/Controllers/StatusItemController+Menu.swift +47 -14
  21. package/Sources/Runic/Controllers/StatusItemController+MenuCards.swift +6 -4
  22. package/Sources/Runic/Controllers/StatusItemController+MenuHelpers.swift +40 -12
  23. package/Sources/Runic/Controllers/StatusItemController.swift +43 -43
  24. package/Sources/Runic/Core/BudgetNotificationManager.swift +2 -1
  25. package/Sources/Runic/Core/Login/ClaudeLoginRunner.swift +2 -2
  26. package/Sources/Runic/Core/Login/CodexLoginRunner.swift +1 -1
  27. package/Sources/Runic/Core/Login/CursorLoginRunner.swift +4 -4
  28. package/Sources/Runic/Core/Login/GeminiLoginRunner.swift +3 -6
  29. package/Sources/Runic/Core/Rendering/IconRenderer.swift +91 -85
  30. package/Sources/Runic/Core/Rendering/IconView.swift +3 -1
  31. package/Sources/Runic/Core/RunicColors.swift +6 -6
  32. package/Sources/Runic/Core/RunicSpacing.swift +7 -7
  33. package/Sources/Runic/Core/RunicTypography.swift +206 -0
  34. package/Sources/Runic/Core/Stores/AuggieTokenStore.swift +10 -36
  35. package/Sources/Runic/Core/Stores/AzureOpenAITokenStore.swift +10 -36
  36. package/Sources/Runic/Core/Stores/CerebrasTokenStore.swift +10 -36
  37. package/Sources/Runic/Core/Stores/CohereTokenStore.swift +10 -36
  38. package/Sources/Runic/Core/Stores/CopilotTokenStore.swift +10 -36
  39. package/Sources/Runic/Core/Stores/CustomProviderStore.swift +10 -10
  40. package/Sources/Runic/Core/Stores/DeepSeekTokenStore.swift +10 -36
  41. package/Sources/Runic/Core/Stores/FireworksTokenStore.swift +10 -36
  42. package/Sources/Runic/Core/Stores/GroqTokenStore.swift +10 -36
  43. package/Sources/Runic/Core/Stores/KimiTokenStore.swift +10 -36
  44. package/Sources/Runic/Core/Stores/MiniMaxCookieHeaderStore.swift +10 -36
  45. package/Sources/Runic/Core/Stores/MiniMaxGroupIDStore.swift +10 -36
  46. package/Sources/Runic/Core/Stores/MiniMaxTokenStore.swift +10 -36
  47. package/Sources/Runic/Core/Stores/MistralTokenStore.swift +10 -36
  48. package/Sources/Runic/Core/Stores/OpenRouterTokenStore.swift +10 -36
  49. package/Sources/Runic/Core/Stores/PerplexityTokenStore.swift +10 -36
  50. package/Sources/Runic/Core/Stores/ProviderToggleStore.swift +1 -1
  51. package/Sources/Runic/Core/Stores/QwenTokenStore.swift +10 -36
  52. package/Sources/Runic/Core/Stores/SambaNovaTokenStore.swift +10 -36
  53. package/Sources/Runic/Core/Stores/SettingsStore.swift +99 -52
  54. package/Sources/Runic/Core/Stores/TogetherTokenStore.swift +10 -36
  55. package/Sources/Runic/Core/Stores/UsageStore+Accessors.swift +19 -6
  56. package/Sources/Runic/Core/Stores/UsageStore+TokenCost.swift +1 -1
  57. package/Sources/Runic/Core/Stores/UsageStore+WidgetSnapshot.swift +1 -1
  58. package/Sources/Runic/Core/Stores/UsageStore.swift +234 -167
  59. package/Sources/Runic/Core/Stores/XAITokenStore.swift +10 -36
  60. package/Sources/Runic/Core/Stores/ZaiTokenStore.swift +10 -36
  61. package/Sources/Runic/Core/UsageExporter.swift +8 -4
  62. package/Sources/Runic/ProviderRegistry.swift +1 -1
  63. package/Sources/Runic/Providers/Antigravity/AntigravityProviderImplementation.swift +1 -1
  64. package/Sources/Runic/Providers/Auggie/AuggieProviderImplementation.swift +1 -1
  65. package/Sources/Runic/Providers/Azure/AzureProviderImplementation.swift +1 -1
  66. package/Sources/Runic/Providers/Bedrock/BedrockProviderImplementation.swift +1 -1
  67. package/Sources/Runic/Providers/Cerebras/CerebrasProviderImplementation.swift +1 -1
  68. package/Sources/Runic/Providers/Codex/CodexProviderImplementation.swift +1 -1
  69. package/Sources/Runic/Providers/Cohere/CohereProviderImplementation.swift +1 -1
  70. package/Sources/Runic/Providers/Cursor/CursorProviderImplementation.swift +1 -1
  71. package/Sources/Runic/Providers/DeepSeek/DeepSeekProviderImplementation.swift +1 -1
  72. package/Sources/Runic/Providers/Factory/FactoryProviderImplementation.swift +1 -1
  73. package/Sources/Runic/Providers/Fireworks/FireworksProviderImplementation.swift +1 -1
  74. package/Sources/Runic/Providers/Gemini/GeminiProviderImplementation.swift +1 -1
  75. package/Sources/Runic/Providers/Groq/GroqProviderImplementation.swift +1 -1
  76. package/Sources/Runic/Providers/Kimi/KimiProviderImplementation.swift +1 -1
  77. package/Sources/Runic/Providers/MiniMax/MiniMaxProviderImplementation.swift +1 -1
  78. package/Sources/Runic/Providers/Mistral/MistralProviderImplementation.swift +1 -1
  79. package/Sources/Runic/Providers/OpenRouter/OpenRouterProviderImplementation.swift +1 -1
  80. package/Sources/Runic/Providers/Perplexity/PerplexityProviderImplementation.swift +1 -1
  81. package/Sources/Runic/Providers/SambaNova/SambaNovaProviderImplementation.swift +1 -1
  82. package/Sources/Runic/Providers/Shared/ProviderImplementation.swift +5 -2
  83. package/Sources/Runic/Providers/Shared/ProviderImplementationRegistry.swift +1 -1
  84. package/Sources/Runic/Providers/Shared/ProviderSettingsDescriptors.swift +1 -1
  85. package/Sources/Runic/Providers/Together/TogetherProviderImplementation.swift +1 -1
  86. package/Sources/Runic/Providers/XAI/XAIProviderImplementation.swift +1 -1
  87. package/Sources/Runic/Providers/Zai/ZaiProviderImplementation.swift +1 -1
  88. package/Sources/Runic/Resources/Fonts/Caveat-Bold.ttf +0 -0
  89. package/Sources/Runic/Resources/Fonts/Caveat-Regular.ttf +0 -0
  90. package/Sources/Runic/Resources/Fonts/FiraCode-Bold.ttf +0 -0
  91. package/Sources/Runic/Resources/Fonts/FiraCode-Light.ttf +0 -0
  92. package/Sources/Runic/Resources/Fonts/FiraCode-Medium.ttf +0 -0
  93. package/Sources/Runic/Resources/Fonts/FiraCode-Regular.ttf +0 -0
  94. package/Sources/Runic/Resources/Fonts/FiraCode-SemiBold.ttf +0 -0
  95. package/Sources/Runic/Resources/Fonts/IBMPlexMono-Bold.ttf +0 -0
  96. package/Sources/Runic/Resources/Fonts/IBMPlexMono-Medium.ttf +0 -0
  97. package/Sources/Runic/Resources/Fonts/IBMPlexMono-Regular.ttf +0 -0
  98. package/Sources/Runic/Resources/Fonts/IBMPlexMono-SemiBold.ttf +0 -0
  99. package/Sources/Runic/Resources/Fonts/Inconsolata-Bold.ttf +0 -0
  100. package/Sources/Runic/Resources/Fonts/Inconsolata-Medium.ttf +0 -0
  101. package/Sources/Runic/Resources/Fonts/Inconsolata-Regular.ttf +0 -0
  102. package/Sources/Runic/Resources/Fonts/Inconsolata-SemiBold.ttf +0 -0
  103. package/Sources/Runic/Resources/Fonts/JetBrainsMono-Bold.ttf +0 -0
  104. package/Sources/Runic/Resources/Fonts/JetBrainsMono-Medium.ttf +0 -0
  105. package/Sources/Runic/Resources/Fonts/JetBrainsMono-Regular.ttf +0 -0
  106. package/Sources/Runic/Resources/Fonts/JetBrainsMono-SemiBold.ttf +0 -0
  107. package/Sources/Runic/Resources/Fonts/SpaceMono-Bold.ttf +0 -0
  108. package/Sources/Runic/Resources/Fonts/SpaceMono-Regular.ttf +0 -0
  109. package/Sources/Runic/Resources/provider-context-windows.json +20 -0
  110. package/Sources/Runic/RunicApp.swift +46 -36
  111. package/Sources/Runic/SessionQuotaNotifications.swift +2 -2
  112. package/Sources/Runic/UsagePaceText.swift +1 -1
  113. package/Sources/Runic/UsageProgressBar.swift +13 -9
  114. package/Sources/Runic/Utilities/LoadingPattern.swift +4 -2
  115. package/Sources/Runic/Utilities/PerformanceConstants.swift +28 -28
  116. package/Sources/Runic/Views/Menu/AlertsMenuView.swift +19 -21
  117. package/Sources/Runic/Views/Menu/CostComparativeChartMenuView.swift +19 -19
  118. package/Sources/Runic/Views/Menu/CostHistoryChartMenuView.swift +7 -7
  119. package/Sources/Runic/Views/Menu/CreditsHistoryChartMenuView.swift +5 -5
  120. package/Sources/Runic/Views/Menu/EfficiencyMetricsMenuView.swift +29 -30
  121. package/Sources/Runic/Views/Menu/HeroStatCardsMenuView.swift +20 -17
  122. package/Sources/Runic/Views/Menu/HourlyActivityChartMenuView.swift +14 -14
  123. package/Sources/Runic/Views/Menu/InlineUsageChartView.swift +15 -20
  124. package/Sources/Runic/Views/Menu/MenuCardEntranceModifier.swift +3 -4
  125. package/Sources/Runic/Views/Menu/MenuCardSidebarView.swift +5 -25
  126. package/Sources/Runic/Views/Menu/MenuCardSkeletonView.swift +1 -1
  127. package/Sources/Runic/Views/Menu/MenuCardView.swift +120 -131
  128. package/Sources/Runic/Views/Menu/MenuContent.swift +11 -8
  129. package/Sources/Runic/Views/Menu/MenuDescriptor.swift +4 -2
  130. package/Sources/Runic/Views/Menu/MenuHighlightStyle.swift +1 -8
  131. package/Sources/Runic/Views/Menu/ModelBreakdownMenuView.swift +20 -14
  132. package/Sources/Runic/Views/Menu/OverviewMenuView.swift +198 -58
  133. package/Sources/Runic/Views/Menu/ProjectBreakdownMenuView.swift +16 -11
  134. package/Sources/Runic/Views/Menu/ProjectBudgetMenuView.swift +27 -27
  135. package/Sources/Runic/Views/Menu/ProviderTabBarView.swift +4 -6
  136. package/Sources/Runic/Views/Menu/SubscriptionUtilizationChartMenuView.swift +24 -11
  137. package/Sources/Runic/Views/Menu/UsageBreakdownChartMenuView.swift +5 -5
  138. package/Sources/Runic/Views/Menu/UsageHeatmapMenuView.swift +7 -8
  139. package/Sources/Runic/Views/Menu/UsageTimelineChartMenuView.swift +28 -76
  140. package/Sources/Runic/Views/Menu/UsageWindowComparisonChartMenuView.swift +8 -7
  141. package/Sources/Runic/Views/Menu/WeeklyActivityChartMenuView.swift +7 -7
  142. package/Sources/Runic/Views/Performance/PerformanceDashboardView.swift +50 -47
  143. package/Sources/Runic/Views/Preferences/LiquidComponents.swift +15 -14
  144. package/Sources/Runic/Views/Preferences/PreferencesAboutPane.swift +7 -7
  145. package/Sources/Runic/Views/Preferences/PreferencesAdvancedPane.swift +27 -27
  146. package/Sources/Runic/Views/Preferences/PreferencesAlertsPane.swift +38 -42
  147. package/Sources/Runic/Views/Preferences/PreferencesAnalyticsPane.swift +39 -43
  148. package/Sources/Runic/Views/Preferences/PreferencesBudgetsPane.swift +21 -21
  149. package/Sources/Runic/Views/Preferences/PreferencesComponents.swift +7 -7
  150. package/Sources/Runic/Views/Preferences/PreferencesCustomProvidersPane.swift +49 -50
  151. package/Sources/Runic/Views/Preferences/PreferencesDebugPane.swift +10 -10
  152. package/Sources/Runic/Views/Preferences/PreferencesGeneralPane.swift +40 -21
  153. package/Sources/Runic/Views/Preferences/PreferencesHelpPane.swift +7 -7
  154. package/Sources/Runic/Views/Preferences/PreferencesIntegrationsPane.swift +108 -33
  155. package/Sources/Runic/Views/Preferences/PreferencesPerformancePane.swift +26 -23
  156. package/Sources/Runic/Views/Preferences/PreferencesProvidersPane.swift +271 -226
  157. package/Sources/Runic/Views/Preferences/PreferencesSelection.swift +6 -2
  158. package/Sources/Runic/Views/Preferences/PreferencesSyncPane.swift +7 -5
  159. package/Sources/Runic/Views/Preferences/PreferencesView.swift +38 -31
  160. package/Sources/Runic/Views/Rating/QualityRatingView.swift +11 -11
  161. package/Sources/Runic/Views/Team/TeamDashboardView.swift +29 -24
  162. package/Sources/Runic/Views/Team/TeamInviteSheet.swift +16 -16
  163. package/Sources/Runic/Views/Team/TeamManagementView.swift +50 -49
  164. package/Sources/Runic/Views/Team/TeamMemberRow.swift +8 -8
  165. package/Sources/RunicCLI/CLIEntry.swift +83 -42
  166. package/Sources/RunicCLI/CLIRenderer.swift +1 -1
  167. package/Sources/RunicCLI/Commands/EnhancedUsageCommand.swift +60 -60
  168. package/Sources/RunicCLI/Commands/ModelsCommand.swift +45 -44
  169. package/Sources/RunicCLI/Commands/ProjectsCommand.swift +83 -69
  170. package/Sources/RunicCLI/Commands/ResetCommand.swift +50 -49
  171. package/Sources/RunicCLI/Commands/UsageLedgerSourceFactory.swift +31 -32
  172. package/Sources/RunicClaudeWebProbe/main.swift +1 -1
  173. package/Sources/RunicCore/AlertRuleStore.swift +20 -20
  174. package/Sources/RunicCore/BrowserCookieImportOrder.swift +3 -3
  175. package/Sources/RunicCore/CostUsageModels.swift +1 -1
  176. package/Sources/RunicCore/CustomProviders/CustomProviderModels.swift +29 -30
  177. package/Sources/RunicCore/CustomProviders/GenericProviderFetcher.swift +80 -71
  178. package/Sources/RunicCore/CustomProviders/ProviderTemplates.swift +53 -109
  179. package/Sources/RunicCore/Host/PTY/TTYCommandRunner.swift +3 -3
  180. package/Sources/RunicCore/Integrations/GitHubIntegration.swift +3 -3
  181. package/Sources/RunicCore/Logging/OSLogLogHandler.swift +6 -6
  182. package/Sources/RunicCore/Models/EnhancedUsageModels.swift +47 -48
  183. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardBrowserCookieImporter.swift +1 -1
  184. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardFetcher.swift +1 -1
  185. package/Sources/RunicCore/Performance/PerformanceModels.swift +4 -4
  186. package/Sources/RunicCore/Performance/PerformanceStorageImpl.swift +81 -64
  187. package/Sources/RunicCore/Policy/UsagePolicyEngine.swift +2 -2
  188. package/Sources/RunicCore/ProjectBudgetStore.swift +15 -12
  189. package/Sources/RunicCore/Providers/Antigravity/AntigravityProviderDescriptor.swift +4 -2
  190. package/Sources/RunicCore/Providers/Antigravity/AntigravityStatusProbe.swift +2 -2
  191. package/Sources/RunicCore/Providers/Auggie/AuggieProviderDescriptor.swift +2 -2
  192. package/Sources/RunicCore/Providers/Auggie/AuggieUsageFetcher.swift +3 -3
  193. package/Sources/RunicCore/Providers/Azure/AzureProviderDescriptor.swift +8 -8
  194. package/Sources/RunicCore/Providers/Azure/AzureUsageFetcher.swift +5 -3
  195. package/Sources/RunicCore/Providers/Bedrock/BedrockProviderDescriptor.swift +6 -6
  196. package/Sources/RunicCore/Providers/Bedrock/BedrockUsageFetcher.swift +3 -7
  197. package/Sources/RunicCore/Providers/Cerebras/CerebrasProviderDescriptor.swift +2 -2
  198. package/Sources/RunicCore/Providers/Cerebras/CerebrasUsageFetcher.swift +2 -2
  199. package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthUsageFetcher.swift +3 -3
  200. package/Sources/RunicCore/Providers/Claude/ClaudeProviderDescriptor.swift +4 -2
  201. package/Sources/RunicCore/Providers/Claude/ClaudeStatusProbe.swift +4 -4
  202. package/Sources/RunicCore/Providers/Claude/ClaudeUsageDataSource.swift +3 -1
  203. package/Sources/RunicCore/Providers/Claude/ClaudeWeb/ClaudeWebAPIFetcher.swift +1 -1
  204. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthCredentials.swift +1 -0
  205. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthUsageFetcher.swift +12 -1
  206. package/Sources/RunicCore/Providers/Codex/CodexProviderDescriptor.swift +4 -2
  207. package/Sources/RunicCore/Providers/Codex/CodexUsageDataSource.swift +3 -1
  208. package/Sources/RunicCore/Providers/Codex/CodexWebDashboardStrategy.swift +5 -3
  209. package/Sources/RunicCore/Providers/Cohere/CohereProviderDescriptor.swift +2 -2
  210. package/Sources/RunicCore/Providers/Cohere/CohereUsageFetcher.swift +3 -3
  211. package/Sources/RunicCore/Providers/Copilot/CopilotGitHubCLITokenReader.swift +7 -4
  212. package/Sources/RunicCore/Providers/Copilot/CopilotProviderDescriptor.swift +4 -4
  213. package/Sources/RunicCore/Providers/Copilot/CopilotUsageFetcher.swift +5 -3
  214. package/Sources/RunicCore/Providers/Copilot/CopilotVSCodeTokenReader.swift +9 -10
  215. package/Sources/RunicCore/Providers/Cursor/CursorProviderDescriptor.swift +4 -2
  216. package/Sources/RunicCore/Providers/Cursor/CursorStatusProbe.swift +1 -0
  217. package/Sources/RunicCore/Providers/DeepSeek/DeepSeekProviderDescriptor.swift +2 -2
  218. package/Sources/RunicCore/Providers/DeepSeek/DeepSeekUsageFetcher.swift +2 -2
  219. package/Sources/RunicCore/Providers/Factory/FactoryLocalStorageImporter.swift +4 -4
  220. package/Sources/RunicCore/Providers/Factory/FactoryProviderDescriptor.swift +4 -2
  221. package/Sources/RunicCore/Providers/Factory/FactoryStatusProbe.swift +3 -2
  222. package/Sources/RunicCore/Providers/Fireworks/FireworksProviderDescriptor.swift +2 -2
  223. package/Sources/RunicCore/Providers/Fireworks/FireworksUsageFetcher.swift +2 -2
  224. package/Sources/RunicCore/Providers/Gemini/GeminiProviderDescriptor.swift +4 -2
  225. package/Sources/RunicCore/Providers/Gemini/GeminiStatusProbe.swift +6 -2
  226. package/Sources/RunicCore/Providers/Groq/GroqProviderDescriptor.swift +2 -2
  227. package/Sources/RunicCore/Providers/Groq/GroqUsageFetcher.swift +2 -2
  228. package/Sources/RunicCore/Providers/Kimi/KimiProviderDescriptor.swift +2 -2
  229. package/Sources/RunicCore/Providers/Kimi/KimiUsageFetcher.swift +2 -2
  230. package/Sources/RunicCore/Providers/MiniMax/MiniMaxProviderDescriptor.swift +10 -5
  231. package/Sources/RunicCore/Providers/MiniMax/MiniMaxUsageFetcher.swift +8 -11
  232. package/Sources/RunicCore/Providers/MiniMax/MiniMaxWebUsageFetcher.swift +10 -10
  233. package/Sources/RunicCore/Providers/Mistral/MistralProviderDescriptor.swift +2 -2
  234. package/Sources/RunicCore/Providers/Mistral/MistralUsageFetcher.swift +2 -2
  235. package/Sources/RunicCore/Providers/OpenRouter/OpenRouterProviderDescriptor.swift +2 -2
  236. package/Sources/RunicCore/Providers/OpenRouter/OpenRouterUsageFetcher.swift +25 -16
  237. package/Sources/RunicCore/Providers/Perplexity/PerplexityProviderDescriptor.swift +2 -2
  238. package/Sources/RunicCore/Providers/Perplexity/PerplexityUsageFetcher.swift +2 -2
  239. package/Sources/RunicCore/Providers/ProviderFetchPlan.swift +2 -2
  240. package/Sources/RunicCore/Providers/ProviderTokenResolver.swift +2 -2
  241. package/Sources/RunicCore/Providers/Qwen/QwenProviderDescriptor.swift +5 -3
  242. package/Sources/RunicCore/Providers/Qwen/QwenUsageStats.swift +27 -16
  243. package/Sources/RunicCore/Providers/SambaNova/SambaNovaProviderDescriptor.swift +2 -2
  244. package/Sources/RunicCore/Providers/SambaNova/SambaNovaUsageFetcher.swift +2 -2
  245. package/Sources/RunicCore/Providers/Together/TogetherProviderDescriptor.swift +2 -2
  246. package/Sources/RunicCore/Providers/Together/TogetherUsageFetcher.swift +2 -2
  247. package/Sources/RunicCore/Providers/VertexAI/VertexAIProviderDescriptor.swift +5 -5
  248. package/Sources/RunicCore/Providers/VertexAI/VertexAISettingsReader.swift +1 -1
  249. package/Sources/RunicCore/Providers/VertexAI/VertexAIUsageFetcher.swift +3 -3
  250. package/Sources/RunicCore/Providers/XAI/XAIProviderDescriptor.swift +2 -2
  251. package/Sources/RunicCore/Providers/XAI/XAIUsageFetcher.swift +2 -2
  252. package/Sources/RunicCore/Providers/Zai/ZaiProviderDescriptor.swift +4 -2
  253. package/Sources/RunicCore/Providers/Zai/ZaiUsageStats.swift +51 -30
  254. package/Sources/RunicCore/Sync/BackgroundSyncManager.swift +76 -77
  255. package/Sources/RunicCore/Sync/SyncConflictResolver.swift +55 -58
  256. package/Sources/RunicCore/Sync/SyncProtocol.swift +21 -22
  257. package/Sources/RunicCore/Sync/SyncRecord.swift +46 -49
  258. package/Sources/RunicCore/Sync/SyncUsageExample.swift +44 -50
  259. package/Sources/RunicCore/Sync/TeamSyncRecords.swift +94 -101
  260. package/Sources/RunicCore/Sync/iCloudSyncEngine.swift +51 -46
  261. package/Sources/RunicCore/Team/TeamModels.swift +111 -110
  262. package/Sources/RunicCore/Team/TeamStore.swift +126 -109
  263. package/Sources/RunicCore/UsageFetcher.swift +2 -2
  264. package/Sources/RunicCore/UsageFormatter.swift +25 -25
  265. package/Sources/RunicCore/UsageLedger/ClaudeUsageLogSource.swift +141 -29
  266. package/Sources/RunicCore/UsageLedger/CodexUsageLogSource.swift +59 -5
  267. package/Sources/RunicCore/UsageLedger/LedgerCache.swift +161 -0
  268. package/Sources/RunicCore/UsageLedger/OTelGenAILedgerAdapter.swift +1 -1
  269. package/Sources/RunicCore/UsageLedger/UsageLedgerAggregator.swift +40 -25
  270. package/Sources/RunicCore/UsageLedger/UsageLedgerInsightsAdvisor.swift +1 -1
  271. package/Sources/RunicCore/UsageLedger/UsageLedgerProjectIdentity.swift +55 -16
  272. package/Sources/RunicCore/Vendored/CostUsage/CostUsageCache.swift +6 -6
  273. package/Sources/RunicCore/Vendored/CostUsage/CostUsageJsonl.swift +1 -1
  274. package/Sources/RunicCore/Vendored/CostUsage/CostUsagePricing.swift +2 -2
  275. package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner.swift +5 -5
  276. package/Tests/RunicTests/AppDelegateTests.swift +8 -3
  277. package/Tests/RunicTests/BrowserCookieOrderLabelTests.swift +2 -3
  278. package/Tests/RunicTests/CLIArgumentParsingTests.swift +3 -4
  279. package/Tests/RunicTests/CLICostTests.swift +6 -7
  280. package/Tests/RunicTests/CLIProviderSelectionTests.swift +2 -3
  281. package/Tests/RunicTests/CLISnapshotTests.swift +3 -4
  282. package/Tests/RunicTests/CLIWebFallbackTests.swift +3 -4
  283. package/Tests/RunicTests/ClaudeOAuthTests.swift +11 -12
  284. package/Tests/RunicTests/ClaudeResilienceTests.swift +3 -4
  285. package/Tests/RunicTests/ClaudeUsageTests.swift +20 -21
  286. package/Tests/RunicTests/CodexOAuthTests.swift +7 -8
  287. package/Tests/RunicTests/CodexUsageLogSourceTests.swift +1 -3
  288. package/Tests/RunicTests/CopilotTokenResolverTests.swift +5 -6
  289. package/Tests/RunicTests/CopilotVSCodeTokenReaderTests.swift +4 -5
  290. package/Tests/RunicTests/CostUsageDecodingTests.swift +15 -17
  291. package/Tests/RunicTests/CostUsagePricingTests.swift +5 -7
  292. package/Tests/RunicTests/CostUsageScannerTests.swift +10 -12
  293. package/Tests/RunicTests/CursorStatusProbeTests.swift +15 -16
  294. package/Tests/RunicTests/FactoryStatusProbeTests.swift +3 -5
  295. package/Tests/RunicTests/GeminiLoginAlertTests.swift +3 -4
  296. package/Tests/RunicTests/GeminiStatusProbeAPITests.swift +11 -11
  297. package/Tests/RunicTests/GeminiStatusProbePlanTests.swift +8 -8
  298. package/Tests/RunicTests/GeminiStatusProbeTests.swift +20 -21
  299. package/Tests/RunicTests/GoogleWorkspaceStatusTests.swift +2 -3
  300. package/Tests/RunicTests/InstallOriginTests.swift +1 -2
  301. package/Tests/RunicTests/KeyboardShortcutsBundleTests.swift +2 -2
  302. package/Tests/RunicTests/LiveAccountTests.swift +3 -3
  303. package/Tests/RunicTests/LoadingPatternTests.swift +3 -4
  304. package/Tests/RunicTests/MenuCardModelTests.swift +33 -34
  305. package/Tests/RunicTests/MiniMaxCookieHeaderStoreTestSupport.swift +4 -1
  306. package/Tests/RunicTests/MiniMaxGroupIDStoreTestSupport.swift +4 -1
  307. package/Tests/RunicTests/MiniMaxParsingTests.swift +4 -5
  308. package/Tests/RunicTests/MiniMaxTokenStoreTestSupport.swift +4 -1
  309. package/Tests/RunicTests/OTelGenAILedgerAdapterTests.swift +4 -6
  310. package/Tests/RunicTests/OpenAIDashboardBrowserCookieImporterTests.swift +1 -2
  311. package/Tests/RunicTests/OpenAIDashboardFetcherCreditsWaitTests.swift +5 -6
  312. package/Tests/RunicTests/OpenAIDashboardOffscreenHostTests.swift +2 -3
  313. package/Tests/RunicTests/OpenAIDashboardParserTests.swift +12 -13
  314. package/Tests/RunicTests/OpenAIWebAccountSwitchTests.swift +17 -6
  315. package/Tests/RunicTests/OpenRouterTokenStoreTestSupport.swift +52 -13
  316. package/Tests/RunicTests/PathBuilderTests.swift +14 -15
  317. package/Tests/RunicTests/ProviderFetchPipelineTests.swift +3 -4
  318. package/Tests/RunicTests/ProviderIconResourcesTests.swift +1 -2
  319. package/Tests/RunicTests/ProviderMetadataStatusLinkTests.swift +1 -2
  320. package/Tests/RunicTests/ProviderSettingsDescriptorTests.swift +53 -19
  321. package/Tests/RunicTests/ProviderToggleStoreTests.swift +10 -11
  322. package/Tests/RunicTests/RunicTests.swift +6 -7
  323. package/Tests/RunicTests/SessionQuotaNotificationLogicTests.swift +5 -6
  324. package/Tests/RunicTests/SettingsStoreTests.swift +149 -45
  325. package/Tests/RunicTests/StatusItemAnimationTests.swift +8 -3
  326. package/Tests/RunicTests/StatusMenuTests.swift +63 -22
  327. package/Tests/RunicTests/StatusProbeTests.swift +28 -29
  328. package/Tests/RunicTests/SubprocessRunnerTests.swift +1 -3
  329. package/Tests/RunicTests/SubscriptionDetectionTests.swift +8 -9
  330. package/Tests/RunicTests/TTYCommandRunnerTests.swift +8 -9
  331. package/Tests/RunicTests/TeamShowbackExporterTests.swift +2 -4
  332. package/Tests/RunicTests/TextParsingTests.swift +1 -2
  333. package/Tests/RunicTests/UsageFormatterTests.swift +15 -16
  334. package/Tests/RunicTests/UsageLedgerAnomalyDetectionTests.swift +12 -14
  335. package/Tests/RunicTests/UsageLedgerForecastTests.swift +4 -6
  336. package/Tests/RunicTests/UsageLedgerInsightsAdvisorTests.swift +7 -9
  337. package/Tests/RunicTests/UsageLedgerProjectNameTests.swift +6 -8
  338. package/Tests/RunicTests/UsagePaceTests.swift +5 -6
  339. package/Tests/RunicTests/UsagePaceTextTests.swift +8 -9
  340. package/Tests/RunicTests/UsagePolicyEngineTests.swift +3 -5
  341. package/Tests/RunicTests/WidgetSnapshotTests.swift +1 -3
  342. package/Tests/RunicTests/ZaiProviderTests.swift +3 -5
  343. package/Tests/RunicTests/ZaiTokenStoreTestSupport.swift +4 -1
  344. package/appcast.xml +36 -37
  345. package/package.json +1 -1
  346. package/runic.png +0 -0
  347. package/runic.svg +15 -0
  348. package/version.env +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.0 — 2026-03-27
4
+ - Typography: custom font system with 7 bundled families (Fira Code, JetBrains Mono, IBM Plex Mono, Space Mono, Inconsolata, Caveat, SF Pro/Mono)
5
+ - Typography: live font switching from Settings > General — no restart needed
6
+ - Typography: RunicTypography design tokens with dynamic RunicFont scale across 600+ font call sites
7
+ - Typography: drop-in font extensibility — add TTF/OTF to Resources/Fonts, rebuild, auto-discovered
8
+ - Typography: font preview in picker — each choice rendered in its own typeface
9
+ - Typography: NSMenuItem post-processor applies selected font to all plain menu items
10
+ - Typography: xLarge dynamic type for slightly larger text across the app
11
+ - Menu: wider card base width (310→340pt) for monospaced font comfort
12
+ - iOS: RunicFont enum for consistent monospaced typography across widgets and views
13
+
3
14
  ## 0.16.1 — 2025-12-29
4
15
  - Menu: reduce layout thrash when opening menus and sizing charts. Thanks @ibehnam!
5
16
  - Packaging: default release notarization builds universal (arm64 + x86_64) zip.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 Srinivas Pendela
3
+ Copyright (c) 2025-2026 Srinivas Pendela
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -24,78 +24,96 @@ Runic sits in your menubar and shows how much of your AI subscription you've use
24
24
 
25
25
  | | | |
26
26
  |---|---|---|
27
- | Claude | Codex | Cursor |
28
- | Gemini | Copilot | z.ai |
29
- | OpenRouter | Groq | DeepSeek |
30
- | Fireworks | Mistral | Perplexity |
31
- | Kimi | Together | Cohere |
32
- | xAI | Cerebras | SambaNova |
27
+ | Claude (1M ctx) | Codex (400K ctx) | Cursor (128K ctx) |
28
+ | Gemini (1M ctx) | Copilot (128K ctx) | z.ai (205K ctx) |
29
+ | OpenRouter | Groq (128K ctx) | DeepSeek (64K ctx) |
30
+ | Fireworks (128K ctx) | Mistral (128K ctx) | Perplexity (128K ctx) |
31
+ | Kimi (128K ctx) | Together (128K ctx) | Cohere (128K ctx) |
32
+ | xAI (128K ctx) | Cerebras (128K ctx) | SambaNova (128K ctx) |
33
33
  | Azure OpenAI | Bedrock | Vertex AI |
34
- | Qwen | MiniMax | Auggie |
34
+ | Qwen (128K ctx) | MiniMax | Auggie |
35
35
  | Antigravity | Factory (Droid) | |
36
36
 
37
+ Context windows are configurable via `Resources/provider-context-windows.json`.
38
+
37
39
  ## Features
38
40
 
39
- **Menu dropdown**
40
- - Provider tab bar with brand icons
41
- - Hero stat with today's token count and cost
42
- - Inline line chart (1h / 6h / 1d / 7d / 30d)
43
- - Glassmorphism stat cards with sparklines
44
- - Usage progress bars with sheen animation
41
+ **Overview dashboard**
42
+ - All providers at a glance with brand icons and progress bars
43
+ - Activity ring showing average usage across providers
44
+ - Context window, reset countdown, and usage window per provider
45
+ - Combined 7-day stacked bar chart
46
+
47
+ **Per-provider view**
48
+ - Hero stat with provider icon, today's token count and cost
49
+ - Inline line chart with 1h / 6h / 1d / 7d / 30d range picker
50
+ - Glassmorphism stat cards (Peak Hour, This Week) with sparklines
51
+ - Usage progress bars with sheen animation and glow effects
45
52
  - Live "Updated Xs ago" timestamp
46
53
 
47
- **Charts**
48
- - Usage timeline (area + line)
49
- - Today by hour (24-bar)
50
- - Last 7 days (weekly bars)
54
+ **Charts** (submenus)
55
+ - Usage timeline (area + line, Catmull-Rom interpolated)
56
+ - Today by hour (24-bar chart with peak highlight)
57
+ - Last 7 days (weekly bar chart)
51
58
  - Subscription utilization (Daily / Weekly / Monthly)
52
- - Usage window comparison (session vs weekly)
53
- - Model breakdown (donut)
54
- - Project breakdown (bar)
59
+ - Usage window comparison (dual-line session vs weekly)
60
+ - Model breakdown (donut chart)
61
+ - Project breakdown (horizontal bar chart)
55
62
 
56
63
  **Analytics**
57
- - Token usage (input, output, cache)
64
+ - Token usage tracking (input, output, cache)
58
65
  - Cost estimation with per-model pricing
59
- - Spend forecasting and budget alerts
66
+ - Spend forecasting with budget breach detection
60
67
  - Project and model attribution
68
+ - Anomaly detection
61
69
 
62
70
  **Export & Notifications**
63
71
  - Export as CSV or JSON
64
72
  - Budget breach alerts via macOS notifications
65
- - macOS widgets
73
+ - macOS widgets (usage, history, compact, switcher)
66
74
  - CLI tool (`RunicCLI`)
67
75
 
68
76
  **Design**
69
77
  - Dark / Light / System theme
70
78
  - Liquid UI with glass materials and animated progress bars
71
- - SF Rounded typography
79
+ - Staggered entrance animations and glass shimmer effects
80
+ - Custom font system — 7 bundled families (Fira Code, JetBrains Mono, IBM Plex Mono, Space Mono, Inconsolata, Caveat, SF Pro/Mono) with live switching
81
+ - Drop-in font extensibility — add TTF/OTF to `Resources/Fonts`, rebuild, auto-discovered
82
+ - Design tokens for typography, colors, spacing, corner radius, animation
72
83
  - VoiceOver accessible
73
84
  - Sparkle auto-updates
74
85
 
75
86
  ## Install
76
87
 
88
+ **Download** the latest release from [GitHub Releases](https://github.com/sriinnu/Runic/releases/latest), unzip, and drag `Runic.app` to Applications. Signed and notarized — no Gatekeeper warnings.
89
+
90
+ **Or build from source:**
91
+
77
92
  ```bash
78
93
  git clone https://github.com/sriinnu/Runic.git
79
94
  cd Runic
80
95
  ./Scripts/compile_and_run.sh
81
96
  ```
82
97
 
83
- Builds the app, signs it, installs to `/Applications`, and launches. The infinity icon appears in your menubar.
84
-
85
98
  ## Configure
86
99
 
87
100
  Open **Preferences** from the menubar. Each provider has its own settings:
88
101
 
89
- - **API-based** (Groq, Mistral, z.ai, etc.): Paste your API key
90
- - **CLI-based** (Claude, Codex): Detected automatically
102
+ - **API-based** (Groq, Mistral, z.ai, etc.): Paste your API key — provider auto-enables
103
+ - **CLI-based** (Claude, Codex): Detected automatically from local CLI
91
104
  - **Cloud** (Bedrock, Vertex AI): Set environment variables
92
105
 
93
- All tokens stored in macOS Keychain — no password prompts.
106
+ All tokens stored in macOS Keychain with no password prompts.
94
107
 
95
108
  ## Privacy
96
109
 
97
110
  Zero telemetry. No analytics. No crash reporting. All data stays on your Mac.
98
111
 
112
+ ## Roadmap
113
+
114
+ - Windows desktop app
115
+ - Web app
116
+
99
117
  ## License
100
118
 
101
119
  MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,24 @@
1
+ import SwiftUI
2
+
3
+ /// iOS font scale — mirrors the macOS RunicFont for cross-platform consistency.
4
+ enum RunicFont {
5
+ static let caption2 = Font.system(.caption2, design: .monospaced)
6
+ static let caption = Font.system(.caption, design: .monospaced)
7
+ static let footnote = Font.system(.footnote, design: .monospaced)
8
+ static let callout = Font.system(.callout, design: .monospaced)
9
+ static let body = Font.system(.body, design: .monospaced)
10
+ static let subheadline = Font.system(.subheadline, design: .monospaced)
11
+ static let headline = Font.system(.headline, design: .monospaced)
12
+ static let title3 = Font.system(.title3, design: .monospaced)
13
+ static let title2 = Font.system(.title2, design: .monospaced)
14
+ static let title = Font.system(.title, design: .monospaced)
15
+ static let largeTitle = Font.system(.largeTitle, design: .monospaced)
16
+
17
+ static func system(size: CGFloat) -> Font {
18
+ Font.system(size: size, design: .monospaced)
19
+ }
20
+
21
+ static func system(size: CGFloat, weight: Font.Weight) -> Font {
22
+ Font.system(size: size, weight: weight, design: .monospaced)
23
+ }
24
+ }
@@ -135,11 +135,11 @@ struct ProviderHeaderView: View {
135
135
 
136
136
  VStack(spacing: 4) {
137
137
  Text("\(Int(snapshot.primary.usedPercent))%")
138
- .font(.system(.largeTitle, design: .rounded, weight: .bold))
138
+ .font(RunicFont.largeTitle.weight(.bold))
139
139
  .foregroundStyle(statusColor)
140
140
 
141
141
  Text("Used")
142
- .font(.caption)
142
+ .font(RunicFont.caption)
143
143
  .foregroundStyle(.secondary)
144
144
  }
145
145
  }
@@ -148,15 +148,15 @@ struct ProviderHeaderView: View {
148
148
  // Status message
149
149
  if snapshot.primary.usedPercent >= 90 {
150
150
  Text("⚠️ Approaching Limit")
151
- .font(.headline)
151
+ .font(RunicFont.headline)
152
152
  .foregroundStyle(.red)
153
153
  } else if snapshot.primary.usedPercent >= 75 {
154
154
  Text("⚡ High Usage")
155
- .font(.headline)
155
+ .font(RunicFont.headline)
156
156
  .foregroundStyle(.orange)
157
157
  } else {
158
158
  Text("✓ Healthy")
159
- .font(.headline)
159
+ .font(RunicFont.headline)
160
160
  .foregroundStyle(.green)
161
161
  }
162
162
  }
@@ -212,10 +212,10 @@ struct MetricRow: View {
212
212
  VStack(alignment: .leading, spacing: 6) {
213
213
  HStack {
214
214
  Text(title)
215
- .font(.subheadline)
215
+ .font(RunicFont.subheadline)
216
216
  Spacer()
217
217
  Text("\(Int(value))%")
218
- .font(.system(.headline, design: .rounded))
218
+ .font(RunicFont.headline)
219
219
  .foregroundStyle(color)
220
220
  }
221
221
 
@@ -232,7 +232,7 @@ struct MetricRow: View {
232
232
  .frame(height: 8)
233
233
 
234
234
  Text(label)
235
- .font(.caption)
235
+ .font(RunicFont.caption)
236
236
  .foregroundStyle(.secondary)
237
237
  }
238
238
  }
@@ -283,7 +283,7 @@ struct AccountTypeBadge: View {
283
283
 
284
284
  var body: some View {
285
285
  Text(type.rawValue.replacingOccurrences(of: "_", with: " ").capitalized)
286
- .font(.caption)
286
+ .font(RunicFont.caption)
287
287
  .padding(.horizontal, 8)
288
288
  .padding(.vertical, 4)
289
289
  .background(color.opacity(0.2))
@@ -120,10 +120,10 @@ struct StatView: View {
120
120
  var body: some View {
121
121
  VStack(spacing: 4) {
122
122
  Text(value)
123
- .font(.system(.title2, design: .rounded, weight: .bold))
123
+ .font(RunicFont.title2.weight(.bold))
124
124
  .foregroundStyle(color)
125
125
  Text(label)
126
- .font(.caption)
126
+ .font(RunicFont.caption)
127
127
  .foregroundStyle(.secondary)
128
128
  }
129
129
  .frame(maxWidth: .infinity)
@@ -147,17 +147,17 @@ struct ProviderRowView: View {
147
147
  HStack {
148
148
  // Provider icon and name
149
149
  Image(systemName: iconForProvider(snapshot.provider))
150
- .font(.title3)
150
+ .font(RunicFont.title3)
151
151
  .foregroundStyle(statusColor)
152
152
  .frame(width: 32)
153
153
 
154
154
  VStack(alignment: .leading, spacing: 2) {
155
155
  Text(snapshot.provider.rawValue.capitalized)
156
- .font(.headline)
156
+ .font(RunicFont.headline)
157
157
 
158
158
  if let email = snapshot.accountEmail {
159
159
  Text(email)
160
- .font(.caption)
160
+ .font(RunicFont.caption)
161
161
  .foregroundStyle(.secondary)
162
162
  }
163
163
  }
@@ -166,7 +166,7 @@ struct ProviderRowView: View {
166
166
 
167
167
  // Usage percentage
168
168
  Text("\(Int(snapshot.primary.usedPercent))%")
169
- .font(.system(.title3, design: .rounded, weight: .semibold))
169
+ .font(RunicFont.title3.weight(.semibold))
170
170
  .foregroundStyle(statusColor)
171
171
  }
172
172
 
@@ -189,9 +189,9 @@ struct ProviderRowView: View {
189
189
  timeRemaining > 0 {
190
190
  HStack {
191
191
  Image(systemName: "clock")
192
- .font(.caption2)
192
+ .font(RunicFont.caption2)
193
193
  Text(resetInfo.resetDescription)
194
- .font(.caption)
194
+ .font(RunicFont.caption)
195
195
  }
196
196
  .foregroundStyle(.secondary)
197
197
  }
@@ -200,9 +200,9 @@ struct ProviderRowView: View {
200
200
  if let model = snapshot.primaryModel {
201
201
  HStack {
202
202
  Image(systemName: "cpu.fill")
203
- .font(.caption2)
203
+ .font(RunicFont.caption2)
204
204
  Text(model.modelName)
205
- .font(.caption)
205
+ .font(RunicFont.caption)
206
206
  }
207
207
  .foregroundStyle(.blue)
208
208
  }
@@ -88,18 +88,18 @@ struct LargeWidgetView: View {
88
88
  // Title and status
89
89
  HStack(spacing: 10) {
90
90
  Image(systemName: entry.systemStatus.iconName)
91
- .font(.system(size: 20, weight: .semibold))
91
+ .font(RunicFont.system(size: 20, weight: .semibold))
92
92
  .foregroundColor(statusColor)
93
93
 
94
94
  Text("Runic Dashboard")
95
- .font(.system(size: 18, weight: .bold))
95
+ .font(RunicFont.system(size: 18, weight: .bold))
96
96
  .foregroundColor(.white)
97
97
 
98
98
  Spacer()
99
99
 
100
100
  // Last update
101
101
  Text("Updated \(relativeTime)")
102
- .font(.system(size: 11, weight: .medium))
102
+ .font(RunicFont.system(size: 11, weight: .medium))
103
103
  .foregroundColor(.white.opacity(0.6))
104
104
  }
105
105
 
@@ -140,15 +140,15 @@ struct LargeWidgetView: View {
140
140
  ) -> some View {
141
141
  HStack(spacing: 6) {
142
142
  Image(systemName: icon)
143
- .font(.system(size: 12))
143
+ .font(RunicFont.system(size: 12))
144
144
  .foregroundColor(color)
145
145
 
146
146
  Text(value)
147
- .font(.system(size: 14, weight: .bold, design: .rounded))
147
+ .font(RunicFont.system(size: 14, weight: .bold))
148
148
  .foregroundColor(.white)
149
149
 
150
150
  Text(label)
151
- .font(.system(size: 11, weight: .medium))
151
+ .font(RunicFont.system(size: 11, weight: .medium))
152
152
  .foregroundColor(.white.opacity(0.6))
153
153
  }
154
154
  }
@@ -158,7 +158,7 @@ struct LargeWidgetView: View {
158
158
  private var chartsView: some View {
159
159
  VStack(alignment: .leading, spacing: 6) {
160
160
  Text("Usage Trend")
161
- .font(.system(size: 11, weight: .semibold))
161
+ .font(RunicFont.system(size: 11, weight: .semibold))
162
162
  .foregroundColor(.white.opacity(0.7))
163
163
 
164
164
  if #available(iOS 16.0, *) {
@@ -193,7 +193,7 @@ struct LargeWidgetView: View {
193
193
  .frame(width: 8, height: 8)
194
194
 
195
195
  Text(provider.displayName)
196
- .font(.system(size: 12, weight: .semibold))
196
+ .font(RunicFont.system(size: 12, weight: .semibold))
197
197
  .foregroundColor(.white)
198
198
 
199
199
  Spacer()
@@ -203,7 +203,7 @@ struct LargeWidgetView: View {
203
203
 
204
204
  // Percentage
205
205
  Text("\(Int(provider.remainingPercent))%")
206
- .font(.system(size: 13, weight: .bold, design: .rounded))
206
+ .font(RunicFont.system(size: 13, weight: .bold))
207
207
  .foregroundColor(.white)
208
208
  .frame(width: 35, alignment: .trailing)
209
209
  }
@@ -225,7 +225,7 @@ struct LargeWidgetView: View {
225
225
  if let countdown = provider.resetCountdown {
226
226
  HStack {
227
227
  Text("Resets \(countdown)")
228
- .font(.system(size: 9, weight: .medium))
228
+ .font(RunicFont.system(size: 9, weight: .medium))
229
229
  .foregroundColor(.white.opacity(0.4))
230
230
 
231
231
  Spacer()
@@ -255,7 +255,7 @@ struct LargeWidgetView: View {
255
255
  }
256
256
 
257
257
  return Image(systemName: "\(icon).circle.fill")
258
- .font(.system(size: 10))
258
+ .font(RunicFont.system(size: 10))
259
259
  .foregroundColor(color)
260
260
  }
261
261
 
@@ -288,9 +288,9 @@ struct LargeWidgetView: View {
288
288
  @ViewBuilder
289
289
  private var emptyStateView: some View {
290
290
  VStack(spacing: 12) {
291
- Image(systemName: "chart.bar.doc.horizontal").font(.system(size: 36)).foregroundColor(.white.opacity(0.3))
292
- Text("No Data Available").font(.system(size: 16, weight: .semibold)).foregroundColor(.white.opacity(0.6))
293
- Text("Open Runic to sync your usage data").font(.system(size: 12)).foregroundColor(.white.opacity(0.4))
291
+ Image(systemName: "chart.bar.doc.horizontal").font(RunicFont.system(size: 36)).foregroundColor(.white.opacity(0.3))
292
+ Text("No Data Available").font(RunicFont.system(size: 16, weight: .semibold)).foregroundColor(.white.opacity(0.6))
293
+ Text("Open Runic to sync your usage data").font(RunicFont.system(size: 12)).foregroundColor(.white.opacity(0.4))
294
294
  }
295
295
  .padding()
296
296
  }
@@ -105,16 +105,16 @@ struct RunicLiveActivity: Widget {
105
105
  VStack(spacing: 12) {
106
106
  HStack {
107
107
  Circle().fill(providerColor(context: context)).frame(width: 10, height: 10)
108
- Text(context.state.providerName).font(.system(size: 15, weight: .semibold)).foregroundColor(.white)
108
+ Text(context.state.providerName).font(RunicFont.system(size: 15, weight: .semibold)).foregroundColor(.white)
109
109
  Spacer()
110
110
  statusBadge(for: context.state.status)
111
111
  }
112
112
 
113
113
  VStack(spacing: 6) {
114
114
  HStack {
115
- Text("Session Usage").font(.system(size: 12, weight: .medium)).foregroundColor(.white.opacity(0.7))
115
+ Text("Session Usage").font(RunicFont.system(size: 12, weight: .medium)).foregroundColor(.white.opacity(0.7))
116
116
  Spacer()
117
- Text("\(Int(context.state.remainingPercent))% remaining").font(.system(size: 12, weight: .semibold)).foregroundColor(.white)
117
+ Text("\(Int(context.state.remainingPercent))% remaining").font(RunicFont.system(size: 12, weight: .semibold)).foregroundColor(.white)
118
118
  }
119
119
  GeometryReader { geometry in
120
120
  ZStack(alignment: .leading) {
@@ -128,20 +128,20 @@ struct RunicLiveActivity: Widget {
128
128
 
129
129
  HStack {
130
130
  HStack(spacing: 4) {
131
- Image(systemName: "clock.fill").font(.system(size: 10)).foregroundColor(.white.opacity(0.6))
132
- Text(sessionDuration(from: context.state.sessionStartTime)).font(.system(size: 11, weight: .medium)).foregroundColor(.white.opacity(0.8))
131
+ Image(systemName: "clock.fill").font(RunicFont.system(size: 10)).foregroundColor(.white.opacity(0.6))
132
+ Text(sessionDuration(from: context.state.sessionStartTime)).font(RunicFont.system(size: 11, weight: .medium)).foregroundColor(.white.opacity(0.8))
133
133
  }
134
134
  Spacer()
135
135
  if let tokens = context.state.sessionTokens {
136
136
  HStack(spacing: 4) {
137
- Image(systemName: "number").font(.system(size: 10)).foregroundColor(.white.opacity(0.6))
138
- Text(UsageFormatter.tokenCountString(tokens)).font(.system(size: 11, weight: .medium)).foregroundColor(.white.opacity(0.8))
137
+ Image(systemName: "number").font(RunicFont.system(size: 10)).foregroundColor(.white.opacity(0.6))
138
+ Text(UsageFormatter.tokenCountString(tokens)).font(RunicFont.system(size: 11, weight: .medium)).foregroundColor(.white.opacity(0.8))
139
139
  }
140
140
  }
141
141
  if let cost = context.state.estimatedCost {
142
142
  HStack(spacing: 4) {
143
- Image(systemName: "dollarsign.circle.fill").font(.system(size: 10)).foregroundColor(.white.opacity(0.6))
144
- Text(UsageFormatter.usdString(cost)).font(.system(size: 11, weight: .medium)).foregroundColor(.white.opacity(0.8))
143
+ Image(systemName: "dollarsign.circle.fill").font(RunicFont.system(size: 10)).foregroundColor(.white.opacity(0.6))
144
+ Text(UsageFormatter.usdString(cost)).font(RunicFont.system(size: 11, weight: .medium)).foregroundColor(.white.opacity(0.8))
145
145
  }
146
146
  }
147
147
  }
@@ -154,10 +154,10 @@ struct RunicLiveActivity: Widget {
154
154
  func expandedLeading(context: ActivityViewContext<RunicLiveActivityAttributes>) -> some View {
155
155
  VStack(alignment: .leading, spacing: 4) {
156
156
  Text(context.state.providerName)
157
- .font(.system(size: 14, weight: .semibold))
157
+ .font(RunicFont.system(size: 14, weight: .semibold))
158
158
 
159
159
  Text(sessionDuration(from: context.state.sessionStartTime))
160
- .font(.system(size: 12, weight: .medium))
160
+ .font(RunicFont.system(size: 12, weight: .medium))
161
161
  .foregroundColor(.secondary)
162
162
  }
163
163
  }
@@ -166,10 +166,10 @@ struct RunicLiveActivity: Widget {
166
166
  func expandedTrailing(context: ActivityViewContext<RunicLiveActivityAttributes>) -> some View {
167
167
  VStack(alignment: .trailing, spacing: 4) {
168
168
  Text("\(Int(context.state.remainingPercent))%")
169
- .font(.system(size: 18, weight: .bold, design: .rounded))
169
+ .font(RunicFont.system(size: 18, weight: .bold))
170
170
 
171
171
  Text("remaining")
172
- .font(.system(size: 11, weight: .medium))
172
+ .font(RunicFont.system(size: 11, weight: .medium))
173
173
  .foregroundColor(.secondary)
174
174
  }
175
175
  }
@@ -196,7 +196,7 @@ struct RunicLiveActivity: Widget {
196
196
  if let cost = context.state.estimatedCost { statItem(icon: "dollarsign.circle", value: UsageFormatter.usdString(cost)) }
197
197
  Spacer()
198
198
  }
199
- .font(.system(size: 11))
199
+ .font(RunicFont.system(size: 11))
200
200
  }
201
201
  }
202
202
 
@@ -210,7 +210,7 @@ struct RunicLiveActivity: Widget {
210
210
  @ViewBuilder
211
211
  func compactTrailing(context: ActivityViewContext<RunicLiveActivityAttributes>) -> some View {
212
212
  Text("\(Int(context.state.remainingPercent))%")
213
- .font(.system(size: 12, weight: .bold, design: .rounded))
213
+ .font(RunicFont.system(size: 12, weight: .bold))
214
214
  }
215
215
 
216
216
  @ViewBuilder
@@ -229,8 +229,8 @@ struct RunicLiveActivity: Widget {
229
229
  ("Complete", Color.blue, "checkmark.circle.fill")
230
230
 
231
231
  return HStack(spacing: 4) {
232
- Image(systemName: icon).font(.system(size: 10))
233
- Text(text).font(.system(size: 11, weight: .semibold))
232
+ Image(systemName: icon).font(RunicFont.system(size: 10))
233
+ Text(text).font(RunicFont.system(size: 11, weight: .semibold))
234
234
  }
235
235
  .foregroundColor(color)
236
236
  .padding(.horizontal, 8).padding(.vertical, 4)
@@ -240,8 +240,8 @@ struct RunicLiveActivity: Widget {
240
240
 
241
241
  private func statItem(icon: String, value: String) -> some View {
242
242
  HStack(spacing: 4) {
243
- Image(systemName: icon).font(.system(size: 10)).foregroundColor(.secondary)
244
- Text(value).font(.system(size: 11, weight: .medium))
243
+ Image(systemName: icon).font(RunicFont.system(size: 10)).foregroundColor(.secondary)
244
+ Text(value).font(RunicFont.system(size: 11, weight: .medium))
245
245
  }
246
246
  }
247
247
 
@@ -78,10 +78,10 @@ struct LockScreenCircularView: View {
78
78
  // Center content
79
79
  VStack(spacing: 1) {
80
80
  Text("\(Int(provider.remainingPercent))")
81
- .font(.system(size: 18, weight: .bold, design: .rounded))
81
+ .font(RunicFont.system(size: 18, weight: .bold))
82
82
 
83
83
  Text("%")
84
- .font(.system(size: 10, weight: .semibold))
84
+ .font(RunicFont.system(size: 10, weight: .semibold))
85
85
  .opacity(0.8)
86
86
  }
87
87
  }
@@ -93,7 +93,7 @@ struct LockScreenCircularView: View {
93
93
  .stroke(Color.white.opacity(0.2), lineWidth: 3)
94
94
 
95
95
  Image(systemName: "exclamationmark.triangle")
96
- .font(.system(size: 16))
96
+ .font(RunicFont.system(size: 16))
97
97
  .opacity(0.5)
98
98
  }
99
99
  }
@@ -127,12 +127,12 @@ struct LockScreenRectangularView: View {
127
127
  // Provider name and percentage
128
128
  HStack {
129
129
  Text(provider.displayName)
130
- .font(.system(size: 13, weight: .semibold))
130
+ .font(RunicFont.system(size: 13, weight: .semibold))
131
131
 
132
132
  Spacer()
133
133
 
134
134
  Text("\(Int(provider.remainingPercent))%")
135
- .font(.system(size: 13, weight: .bold, design: .rounded))
135
+ .font(RunicFont.system(size: 13, weight: .bold))
136
136
  }
137
137
 
138
138
  // Progress bar
@@ -151,11 +151,11 @@ struct LockScreenRectangularView: View {
151
151
  // Reset countdown
152
152
  if let countdown = provider.resetCountdown {
153
153
  Text("Resets \(countdown)")
154
- .font(.system(size: 11, weight: .medium))
154
+ .font(RunicFont.system(size: 11, weight: .medium))
155
155
  .opacity(0.7)
156
156
  } else {
157
157
  Text("Updated \(relativeTime(from: provider.updatedAt))")
158
- .font(.system(size: 11, weight: .medium))
158
+ .font(RunicFont.system(size: 11, weight: .medium))
159
159
  .opacity(0.7)
160
160
  }
161
161
  }
@@ -165,14 +165,14 @@ struct LockScreenRectangularView: View {
165
165
  VStack(alignment: .leading, spacing: 4) {
166
166
  HStack {
167
167
  Image(systemName: "exclamationmark.triangle")
168
- .font(.system(size: 12))
168
+ .font(RunicFont.system(size: 12))
169
169
 
170
170
  Text("No Data")
171
- .font(.system(size: 13, weight: .semibold))
171
+ .font(RunicFont.system(size: 13, weight: .semibold))
172
172
  }
173
173
 
174
174
  Text("Open Runic to sync")
175
- .font(.system(size: 11))
175
+ .font(RunicFont.system(size: 11))
176
176
  .opacity(0.6)
177
177
  }
178
178
  }
@@ -214,21 +214,21 @@ struct LockScreenInlineView: View {
214
214
  if let provider = primaryProvider {
215
215
  HStack(spacing: 4) {
216
216
  Image(systemName: statusIcon(for: provider))
217
- .font(.system(size: 12))
217
+ .font(RunicFont.system(size: 12))
218
218
 
219
219
  Text("\(provider.displayName):")
220
- .font(.system(size: 12, weight: .medium))
220
+ .font(RunicFont.system(size: 12, weight: .medium))
221
221
 
222
222
  Text("\(Int(provider.remainingPercent))% left")
223
- .font(.system(size: 12, weight: .semibold))
223
+ .font(RunicFont.system(size: 12, weight: .semibold))
224
224
  }
225
225
  } else {
226
226
  HStack(spacing: 4) {
227
227
  Image(systemName: "exclamationmark.triangle")
228
- .font(.system(size: 12))
228
+ .font(RunicFont.system(size: 12))
229
229
 
230
230
  Text("Runic: No data")
231
- .font(.system(size: 12, weight: .medium))
231
+ .font(RunicFont.system(size: 12, weight: .medium))
232
232
  }
233
233
  }
234
234
  }