@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
@@ -33,7 +33,7 @@ public actor GenericProviderFetcher {
33
33
  request.setValue("application/json", forHTTPHeaderField: "Content-Type")
34
34
 
35
35
  // Add auth headers
36
- try await addAuthHeaders(to: &request)
36
+ try await self.addAuthHeaders(to: &request)
37
37
 
38
38
  // 3. Make request
39
39
  let (data, response) = try await URLSession.shared.data(for: request)
@@ -52,7 +52,7 @@ public actor GenericProviderFetcher {
52
52
  }
53
53
 
54
54
  // 5. Extract fields using mapping
55
- return try extractUsageData(from: json, mapping: endpoint.mapping)
55
+ return try self.extractUsageData(from: json, mapping: endpoint.mapping)
56
56
  }
57
57
 
58
58
  /// Fetch balance data from the custom provider
@@ -70,7 +70,7 @@ public actor GenericProviderFetcher {
70
70
  request.setValue("application/json", forHTTPHeaderField: "Content-Type")
71
71
 
72
72
  // Add auth headers
73
- try await addAuthHeaders(to: &request)
73
+ try await self.addAuthHeaders(to: &request)
74
74
 
75
75
  // 3. Make request
76
76
  let (data, response) = try await URLSession.shared.data(for: request)
@@ -89,34 +89,31 @@ public actor GenericProviderFetcher {
89
89
  }
90
90
 
91
91
  // 5. Extract fields using mapping
92
- return try extractBalanceData(from: json, mapping: endpoint.mapping)
92
+ return try self.extractBalanceData(from: json, mapping: endpoint.mapping)
93
93
  }
94
94
 
95
95
  /// Convert usage data to Runic's UsageSnapshot format
96
96
  public func toUsageSnapshot(_ data: UsageData) -> UsageSnapshot {
97
- let usedPercent: Double
98
- if let quota = data.quota, let used = data.used, quota > 0 {
99
- usedPercent = (used / quota) * 100.0
97
+ let usedPercent: Double = if let quota = data.quota, let used = data.used, quota > 0 {
98
+ (used / quota) * 100.0
100
99
  } else if let remaining = data.remaining, let quota = data.quota, quota > 0 {
101
- usedPercent = ((quota - remaining) / quota) * 100.0
100
+ ((quota - remaining) / quota) * 100.0
102
101
  } else {
103
- usedPercent = 0
102
+ 0
104
103
  }
105
104
 
106
105
  let primary = RateWindow(
107
106
  usedPercent: max(0, min(100, usedPercent)),
108
107
  windowMinutes: nil,
109
108
  resetsAt: data.resetDate,
110
- resetDescription: data.resetDate.map { resetDescription(from: $0) }
111
- )
109
+ resetDescription: data.resetDate.map { self.resetDescription(from: $0) })
112
110
 
113
111
  return UsageSnapshot(
114
112
  primary: primary,
115
113
  secondary: nil,
116
114
  tertiary: nil,
117
115
  updatedAt: Date(),
118
- identity: nil
119
- )
116
+ identity: nil)
120
117
  }
121
118
 
122
119
  // MARK: - URL Building
@@ -126,7 +123,7 @@ public actor GenericProviderFetcher {
126
123
  var urlString = template
127
124
 
128
125
  // Replace date variables
129
- urlString = try substituteDateVariables(in: urlString)
126
+ urlString = try self.substituteDateVariables(in: urlString)
130
127
 
131
128
  // Build URL components
132
129
  guard var components = URLComponents(string: urlString) else {
@@ -134,7 +131,7 @@ public actor GenericProviderFetcher {
134
131
  }
135
132
 
136
133
  // Add query parameters
137
- if let params = params, !params.isEmpty {
134
+ if let params, !params.isEmpty {
138
135
  var queryItems = components.queryItems ?? []
139
136
  queryItems.append(contentsOf: params.map { URLQueryItem(name: $0.key, value: $0.value) })
140
137
  components.queryItems = queryItems
@@ -205,10 +202,10 @@ public actor GenericProviderFetcher {
205
202
  let token = try await loadToken()
206
203
 
207
204
  // Add auth header based on type
208
- switch config.auth.type {
205
+ switch self.config.auth.type {
209
206
  case .apiKey:
210
207
  let value = (config.auth.headerPrefix ?? "") + token
211
- request.setValue(value, forHTTPHeaderField: config.auth.headerName)
208
+ request.setValue(value, forHTTPHeaderField: self.config.auth.headerName)
212
209
 
213
210
  case .bearer:
214
211
  request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
@@ -224,11 +221,11 @@ public actor GenericProviderFetcher {
224
221
  case .custom:
225
222
  // Custom auth uses the exact header name and prefix from config
226
223
  let value = (config.auth.headerPrefix ?? "") + token
227
- request.setValue(value, forHTTPHeaderField: config.auth.headerName)
224
+ request.setValue(value, forHTTPHeaderField: self.config.auth.headerName)
228
225
  }
229
226
 
230
227
  // Add additional headers
231
- config.auth.additionalHeaders?.forEach { key, value in
228
+ self.config.auth.additionalHeaders?.forEach { key, value in
232
229
  request.setValue(value, forHTTPHeaderField: key)
233
230
  }
234
231
  }
@@ -241,12 +238,12 @@ public actor GenericProviderFetcher {
241
238
  }
242
239
 
243
240
  // Try environment variable
244
- let envKey = config.auth.tokenKeychain.uppercased().replacingOccurrences(of: "-", with: "_")
241
+ let envKey = self.config.auth.tokenKeychain.uppercased().replacingOccurrences(of: "-", with: "_")
245
242
  if let token = ProcessInfo.processInfo.environment[envKey] {
246
243
  return token.trimmingCharacters(in: .whitespacesAndNewlines)
247
244
  }
248
245
 
249
- throw FetchError.missingToken(config.auth.tokenKeychain)
246
+ throw FetchError.missingToken(self.config.auth.tokenKeychain)
250
247
  }
251
248
 
252
249
  /// Read token from keychain
@@ -255,18 +252,18 @@ public actor GenericProviderFetcher {
255
252
  var result: CFTypeRef?
256
253
  var query: [String: Any] = [
257
254
  kSecClass as String: kSecClassGenericPassword,
258
- kSecAttrService as String: keychainService,
255
+ kSecAttrService as String: self.keychainService,
259
256
  kSecAttrAccount as String: account,
260
257
  kSecUseDataProtectionKeychain as String: true,
261
258
  kSecUseAuthenticationUI as String: "kSecUseAuthenticationUIFail" as CFString,
262
259
  kSecMatchLimit as String: kSecMatchLimitOne,
263
260
  kSecReturnData as String: true,
264
261
  ]
265
- #if canImport(LocalAuthentication)
262
+ #if canImport(LocalAuthentication)
266
263
  let authContext = LAContext()
267
264
  authContext.interactionNotAllowed = true
268
265
  query[kSecUseAuthenticationContext as String] = authContext
269
- #endif
266
+ #endif
270
267
 
271
268
  let status = SecItemCopyMatching(query as CFDictionary, &result)
272
269
  if status == errSecItemNotFound {
@@ -276,7 +273,7 @@ public actor GenericProviderFetcher {
276
273
  return nil
277
274
  }
278
275
  guard status == errSecSuccess else {
279
- log.error("Keychain read failed for \(account): \(status)")
276
+ self.log.error("Keychain read failed for \(account): \(status)")
280
277
  return nil
281
278
  }
282
279
 
@@ -303,32 +300,32 @@ public actor GenericProviderFetcher {
303
300
 
304
301
  // Extract quota
305
302
  if let quotaPath = mapping.quota {
306
- data.quota = extractDouble(from: json, path: quotaPath, nested: mapping.nestedPaths)
303
+ data.quota = self.extractDouble(from: json, path: quotaPath, nested: mapping.nestedPaths)
307
304
  }
308
305
 
309
306
  // Extract used amount
310
307
  if let usedPath = mapping.used {
311
- data.used = extractDouble(from: json, path: usedPath, nested: mapping.nestedPaths)
308
+ data.used = self.extractDouble(from: json, path: usedPath, nested: mapping.nestedPaths)
312
309
  }
313
310
 
314
311
  // Extract remaining amount
315
312
  if let remainingPath = mapping.remaining {
316
- data.remaining = extractDouble(from: json, path: remainingPath, nested: mapping.nestedPaths)
313
+ data.remaining = self.extractDouble(from: json, path: remainingPath, nested: mapping.nestedPaths)
317
314
  }
318
315
 
319
316
  // Extract cost
320
317
  if let costPath = mapping.cost {
321
- data.cost = extractDouble(from: json, path: costPath, nested: mapping.nestedPaths)
318
+ data.cost = self.extractDouble(from: json, path: costPath, nested: mapping.nestedPaths)
322
319
  }
323
320
 
324
321
  // Extract reset date
325
322
  if let resetPath = mapping.resetDate {
326
- data.resetDate = extractDate(from: json, path: resetPath, nested: mapping.nestedPaths)
323
+ data.resetDate = self.extractDate(from: json, path: resetPath, nested: mapping.nestedPaths)
327
324
  }
328
325
 
329
326
  // Extract tokens
330
327
  if let tokensPath = mapping.tokens {
331
- data.tokens = extractInt(from: json, path: tokensPath, nested: mapping.nestedPaths)
328
+ data.tokens = self.extractInt(from: json, path: tokensPath, nested: mapping.nestedPaths)
332
329
  }
333
330
 
334
331
  return data
@@ -340,11 +337,11 @@ public actor GenericProviderFetcher {
340
337
 
341
338
  // Extract balance (use 'remaining' or 'used' mapping)
342
339
  if let balancePath = mapping.remaining ?? mapping.used {
343
- data.balance = extractDouble(from: json, path: balancePath, nested: mapping.nestedPaths)
340
+ data.balance = self.extractDouble(from: json, path: balancePath, nested: mapping.nestedPaths)
344
341
  }
345
342
 
346
343
  // Try to detect currency from response
347
- data.currency = extractString(from: json, path: "currency", nested: true) ?? "USD"
344
+ data.currency = self.extractString(from: json, path: "currency", nested: true) ?? "USD"
348
345
 
349
346
  return data
350
347
  }
@@ -363,14 +360,16 @@ public actor GenericProviderFetcher {
363
360
  for component in components {
364
361
  // Handle array indexing: field[0]
365
362
  if let bracketIndex = component.firstIndex(of: "["),
366
- let closeBracket = component.firstIndex(of: "]") {
363
+ let closeBracket = component.firstIndex(of: "]")
364
+ {
367
365
  let fieldName = String(component[..<bracketIndex])
368
366
  let indexStr = String(component[component.index(after: bracketIndex)..<closeBracket])
369
367
 
370
368
  guard let dict = current as? [String: Any],
371
369
  let array = dict[fieldName] as? [Any],
372
370
  let index = Int(indexStr),
373
- index < array.count else {
371
+ index < array.count
372
+ else {
374
373
  return nil
375
374
  }
376
375
  current = array[index]
@@ -520,8 +519,8 @@ public struct UsageData: Sendable {
520
519
  remaining: Double? = nil,
521
520
  cost: Double? = nil,
522
521
  resetDate: Date? = nil,
523
- tokens: Int? = nil
524
- ) {
522
+ tokens: Int? = nil)
523
+ {
525
524
  self.quota = quota
526
525
  self.used = used
527
526
  self.remaining = remaining
@@ -531,14 +530,13 @@ public struct UsageData: Sendable {
531
530
  }
532
531
 
533
532
  public func toCustomUsageData() -> CustomUsageData {
534
- return CustomUsageData(
533
+ CustomUsageData(
535
534
  quota: self.quota,
536
535
  used: self.used,
537
536
  remaining: self.remaining,
538
537
  cost: self.cost,
539
538
  resetDate: self.resetDate,
540
- tokens: self.tokens
541
- )
539
+ tokens: self.tokens)
542
540
  }
543
541
  }
544
542
 
@@ -571,63 +569,63 @@ public enum FetchError: LocalizedError, Sendable {
571
569
  public var errorDescription: String? {
572
570
  switch self {
573
571
  case .noUsageEndpoint:
574
- return "No usage endpoint configured for this provider"
572
+ "No usage endpoint configured for this provider"
575
573
  case .noBalanceEndpoint:
576
- return "No balance endpoint configured for this provider"
577
- case .invalidURL(let url):
578
- return "Invalid URL: \(url)"
574
+ "No balance endpoint configured for this provider"
575
+ case let .invalidURL(url):
576
+ "Invalid URL: \(url)"
579
577
  case .invalidResponse:
580
- return "Invalid response from provider API"
581
- case .httpError(let code):
582
- return "HTTP error \(code) from provider API"
578
+ "Invalid response from provider API"
579
+ case let .httpError(code):
580
+ "HTTP error \(code) from provider API"
583
581
  case .invalidJSON:
584
- return "Failed to parse JSON response from provider"
585
- case .missingToken(let account):
586
- return "No API token found for '\(account)'. Store it in Keychain or set as environment variable."
582
+ "Failed to parse JSON response from provider"
583
+ case let .missingToken(account):
584
+ "No API token found for '\(account)'. Store it in Keychain or set as environment variable."
587
585
  case .invalidDateRange:
588
- return "Failed to calculate date range for URL template"
589
- case .extractionFailed(let field):
590
- return "Failed to extract field '\(field)' from response"
591
- case .insecureURL(let url):
592
- return "Only HTTPS URLs are allowed. Got: \(url)"
586
+ "Failed to calculate date range for URL template"
587
+ case let .extractionFailed(field):
588
+ "Failed to extract field '\(field)' from response"
589
+ case let .insecureURL(url):
590
+ "Only HTTPS URLs are allowed. Got: \(url)"
593
591
  }
594
592
  }
595
593
 
596
594
  public var failureReason: String? {
597
595
  switch self {
598
- case .missingToken(let account):
599
- return "The token for account '\(account)' is not configured in Keychain or environment variables"
600
- case .httpError(let code):
601
- return "The server returned HTTP status code \(code)"
596
+ case let .missingToken(account):
597
+ "The token for account '\(account)' is not configured in Keychain or environment variables"
598
+ case let .httpError(code):
599
+ "The server returned HTTP status code \(code)"
602
600
  case .invalidJSON:
603
- return "The response is not valid JSON or has unexpected structure"
604
- case .extractionFailed(let field):
605
- return "The field '\(field)' was not found in the response or has wrong type"
601
+ "The response is not valid JSON or has unexpected structure"
602
+ case let .extractionFailed(field):
603
+ "The field '\(field)' was not found in the response or has wrong type"
606
604
  case .insecureURL:
607
- return "The URL scheme is not HTTPS"
605
+ "The URL scheme is not HTTPS"
608
606
  default:
609
- return nil
607
+ nil
610
608
  }
611
609
  }
612
610
 
613
611
  public var recoverySuggestion: String? {
614
612
  switch self {
615
- case .missingToken(let account):
616
- return "Store your API token in Keychain with account name '\(account)' or set it as environment variable"
613
+ case let .missingToken(account):
614
+ "Store your API token in Keychain with account name '\(account)' or set it as environment variable"
617
615
  case .noUsageEndpoint:
618
- return "Configure a usage endpoint in the provider settings"
616
+ "Configure a usage endpoint in the provider settings"
619
617
  case .noBalanceEndpoint:
620
- return "Configure a balance endpoint in the provider settings"
621
- case .httpError(let code) where code == 401:
622
- return "Check that your API token is valid and has not expired"
623
- case .httpError(let code) where code == 429:
624
- return "You have been rate limited. Try again later."
618
+ "Configure a balance endpoint in the provider settings"
619
+ case let .httpError(code) where code == 401:
620
+ "Check that your API token is valid and has not expired"
621
+ case let .httpError(code) where code == 429:
622
+ "You have been rate limited. Try again later."
625
623
  case .invalidJSON:
626
- return "Check the API endpoint URL and response mapping configuration"
624
+ "Check the API endpoint URL and response mapping configuration"
627
625
  case .insecureURL:
628
- return "Change the provider URL to use HTTPS (e.g., https://api.example.com)"
626
+ "Change the provider URL to use HTTPS (e.g., https://api.example.com)"
629
627
  default:
630
- return nil
628
+ nil
631
629
  }
632
630
  }
633
631
  }