@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
@@ -18,7 +18,7 @@ public struct MiniMaxModelRemain: Decodable {
18
18
  public let modelName: String
19
19
  public let currentIntervalTotalCount: Int
20
20
  public let currentIntervalUsageCount: Int
21
-
21
+
22
22
  enum CodingKeys: String, CodingKey {
23
23
  case modelName = "model_name"
24
24
  case currentIntervalTotalCount = "current_interval_total_count"
@@ -62,9 +62,9 @@ extension MiniMaxUsageSnapshot {
62
62
  // But let's assume standard "usage" field naming means USED.
63
63
  // If the user reports it shows 100% when new, we invert it.
64
64
  // For now, let's map it as Used/Total.
65
-
65
+
66
66
  let percent = self.total > 0 ? (Double(self.used) / Double(self.total)) * 100.0 : 0.0
67
-
67
+
68
68
  let primary = RateWindow(
69
69
  usedPercent: percent,
70
70
  windowMinutes: 24 * 60,
@@ -77,7 +77,7 @@ extension MiniMaxUsageSnapshot {
77
77
  accountEmail: nil,
78
78
  accountOrganization: nil,
79
79
  loginMethod: "api-key")
80
-
80
+
81
81
  return UsageSnapshot(
82
82
  primary: primary,
83
83
  secondary: nil,
@@ -126,11 +126,11 @@ public struct MiniMaxUsageFetcher: Sendable {
126
126
  let apiResponse = try decoder.decode(MiniMaxQuotaResponse.self, from: data)
127
127
 
128
128
  if apiResponse.baseResponse.statusCode != 0 {
129
- throw MiniMaxUsageError.apiError(apiResponse.baseResponse.statusMsg)
129
+ throw MiniMaxUsageError.apiError(apiResponse.baseResponse.statusMsg)
130
130
  }
131
131
 
132
132
  guard let firstModel = apiResponse.modelRemains?.first else {
133
- throw MiniMaxUsageError.parseFailed("No model quota found")
133
+ throw MiniMaxUsageError.parseFailed("No model quota found")
134
134
  }
135
135
 
136
136
  return MiniMaxUsageSnapshot(
@@ -138,7 +138,7 @@ public struct MiniMaxUsageFetcher: Sendable {
138
138
  used: firstModel.currentIntervalUsageCount,
139
139
  modelName: firstModel.modelName,
140
140
  updatedAt: Date())
141
-
141
+
142
142
  } catch {
143
143
  Self.log.error("MiniMax parsing error: \(error.localizedDescription)")
144
144
  throw MiniMaxUsageError.parseFailed(error.localizedDescription)
@@ -225,13 +225,13 @@ public struct MiniMaxWebUsageFetcher: Sendable {
225
225
 
226
226
  // MARK: - Parsing helpers
227
227
 
228
- struct MiniMaxManualInput: Sendable {
228
+ struct MiniMaxManualInput {
229
229
  let cookieHeader: String
230
230
  let accessToken: String?
231
231
  let groupID: String?
232
232
  }
233
233
 
234
- struct MiniMaxParsedUsage: Sendable {
234
+ struct MiniMaxParsedUsage {
235
235
  let usedPercent: Double
236
236
  let windowMinutes: Int?
237
237
  let resetsAt: Date?
@@ -408,9 +408,9 @@ enum MiniMaxWebParsing {
408
408
  if let remaining = self.captureGroups(
409
409
  in: html,
410
410
  pattern: "(?i)Available usage[^0-9]*([0-9]+(?:\\.[0-9]+)?)")?.first,
411
- let total = self.captureGroups(
412
- in: html,
413
- pattern: "(?i)Total usage[^0-9]*([0-9]+(?:\\.[0-9]+)?)")?.first
411
+ let total = self.captureGroups(
412
+ in: html,
413
+ pattern: "(?i)Total usage[^0-9]*([0-9]+(?:\\.[0-9]+)?)")?.first
414
414
  {
415
415
  let remainingValue = self.doubleValue(remaining) ?? 0
416
416
  let totalValue = self.doubleValue(total) ?? 0
@@ -613,7 +613,7 @@ enum MiniMaxWebParsing {
613
613
  }
614
614
 
615
615
  #if os(macOS)
616
- private struct MiniMaxWebSession: Sendable {
616
+ private struct MiniMaxWebSession {
617
617
  let cookieHeader: String
618
618
  let accessToken: String?
619
619
  let groupID: String?
@@ -621,7 +621,7 @@ private struct MiniMaxWebSession: Sendable {
621
621
  let isManual: Bool
622
622
  }
623
623
 
624
- private struct MiniMaxCookieSession: Sendable {
624
+ private struct MiniMaxCookieSession {
625
625
  let cookieHeader: String
626
626
  let sourceLabel: String
627
627
  }
@@ -674,7 +674,7 @@ private enum MiniMaxCookieImporter {
674
674
  }
675
675
  }
676
676
 
677
- private struct MiniMaxLocalStorageToken: Sendable {
677
+ private struct MiniMaxLocalStorageToken {
678
678
  let accessToken: String
679
679
  let groupID: String?
680
680
  let sourceLabel: String
@@ -706,7 +706,7 @@ private enum MiniMaxLocalStorageImporter {
706
706
  return tokens
707
707
  }
708
708
 
709
- private struct LocalStorageCandidate: Sendable {
709
+ private struct LocalStorageCandidate {
710
710
  let label: String
711
711
  let levelDBURL: URL
712
712
  }
@@ -789,7 +789,7 @@ private enum MiniMaxLocalStorageImporter {
789
789
  }
790
790
  }
791
791
 
792
- private struct TokenMatch: Sendable {
792
+ private struct TokenMatch {
793
793
  let accessToken: String
794
794
  let groupID: String?
795
795
  }
@@ -1,5 +1,5 @@
1
- import RunicMacroSupport
2
1
  import Foundation
2
+ import RunicMacroSupport
3
3
 
4
4
  @ProviderDescriptorRegistration
5
5
  @ProviderDescriptorDefinition
@@ -71,7 +71,7 @@ struct MistralAPIFetchStrategy: ProviderFetchStrategy {
71
71
  }
72
72
  }
73
73
 
74
- enum MistralSettingsError: LocalizedError, Sendable {
74
+ enum MistralSettingsError: LocalizedError {
75
75
  case missingToken
76
76
 
77
77
  var errorDescription: String? {
@@ -8,7 +8,7 @@ struct MistralModelsResponse: Decodable {
8
8
  }
9
9
  }
10
10
 
11
- struct MistralUsageFetcher {
11
+ enum MistralUsageFetcher {
12
12
  static let apiURL = URL(string: "https://api.mistral.ai/v1/models")!
13
13
 
14
14
  static func fetchModels(apiKey: String) async throws -> MistralModelsResponse {
@@ -57,7 +57,7 @@ extension MistralModelsResponse {
57
57
  }
58
58
  }
59
59
 
60
- enum MistralAPIError: LocalizedError, Sendable {
60
+ enum MistralAPIError: LocalizedError {
61
61
  case invalidResponse
62
62
  case httpError(statusCode: Int, body: String?)
63
63
 
@@ -1,5 +1,5 @@
1
- import RunicMacroSupport
2
1
  import Foundation
2
+ import RunicMacroSupport
3
3
 
4
4
  @ProviderDescriptorRegistration
5
5
  @ProviderDescriptorDefinition
@@ -74,7 +74,7 @@ struct OpenRouterAPIFetchStrategy: ProviderFetchStrategy {
74
74
 
75
75
  // MARK: - Settings Errors
76
76
 
77
- enum OpenRouterSettingsError: LocalizedError, Sendable {
77
+ enum OpenRouterSettingsError: LocalizedError {
78
78
  case missingToken
79
79
 
80
80
  var errorDescription: String? {
@@ -51,16 +51,30 @@ struct OpenRouterKeyInfoResponse: Decodable {
51
51
  }
52
52
  }
53
53
 
54
- var keyUsage: Double { self.data?.usage ?? 0 }
55
- var keyLimit: Double? { self.data?.limit }
56
- var isFreeTier: Bool { self.data?.is_free_tier ?? false }
57
- var rateLimitRequests: Int? { self.data?.rate_limit?.requests }
58
- var rateLimitInterval: String? { self.data?.rate_limit?.interval }
54
+ var keyUsage: Double {
55
+ self.data?.usage ?? 0
56
+ }
57
+
58
+ var keyLimit: Double? {
59
+ self.data?.limit
60
+ }
61
+
62
+ var isFreeTier: Bool {
63
+ self.data?.is_free_tier ?? false
64
+ }
65
+
66
+ var rateLimitRequests: Int? {
67
+ self.data?.rate_limit?.requests
68
+ }
69
+
70
+ var rateLimitInterval: String? {
71
+ self.data?.rate_limit?.interval
72
+ }
59
73
  }
60
74
 
61
75
  // MARK: - Fetcher
62
76
 
63
- struct OpenRouterUsageFetcher {
77
+ enum OpenRouterUsageFetcher {
64
78
  static let creditsURL = URL(string: "https://openrouter.ai/api/v1/credits")!
65
79
  static let keyInfoURL = URL(string: "https://openrouter.ai/api/v1/auth/key")!
66
80
  private static let requestTimeout: TimeInterval = 15
@@ -98,9 +112,9 @@ struct OpenRouterUsageFetcher {
98
112
 
99
113
  private static func fetchKeyInfoBestEffort(apiKey: String) async -> OpenRouterKeyInfoResponse? {
100
114
  do {
101
- return try await Self.fetchKeyInfo(apiKey: apiKey)
115
+ return try await self.fetchKeyInfo(apiKey: apiKey)
102
116
  } catch {
103
- Self.log.info("OpenRouter key info unavailable: \(error.localizedDescription)")
117
+ self.log.info("OpenRouter key info unavailable: \(error.localizedDescription)")
104
118
  return nil
105
119
  }
106
120
  }
@@ -124,7 +138,6 @@ struct OpenRouterUsageFetcher {
124
138
 
125
139
  return try JSONDecoder().decode(OpenRouterKeyInfoResponse.self, from: data)
126
140
  }
127
-
128
141
  }
129
142
 
130
143
  // MARK: - Snapshot conversion
@@ -185,7 +198,7 @@ extension OpenRouterCreditsResponse {
185
198
 
186
199
  // MARK: - Errors
187
200
 
188
- enum OpenRouterAPIError: LocalizedError, Sendable {
201
+ enum OpenRouterAPIError: LocalizedError {
189
202
  case invalidResponse
190
203
  case httpError(statusCode: Int)
191
204
  case decodingError
@@ -1,5 +1,5 @@
1
- import RunicMacroSupport
2
1
  import Foundation
2
+ import RunicMacroSupport
3
3
 
4
4
  @ProviderDescriptorRegistration
5
5
  @ProviderDescriptorDefinition
@@ -71,7 +71,7 @@ struct PerplexityAPIFetchStrategy: ProviderFetchStrategy {
71
71
  }
72
72
  }
73
73
 
74
- enum PerplexitySettingsError: LocalizedError, Sendable {
74
+ enum PerplexitySettingsError: LocalizedError {
75
75
  case missingToken
76
76
 
77
77
  var errorDescription: String? {
@@ -8,7 +8,7 @@ struct PerplexityModelsResponse: Decodable {
8
8
  }
9
9
  }
10
10
 
11
- struct PerplexityUsageFetcher {
11
+ enum PerplexityUsageFetcher {
12
12
  static let apiURL = URL(string: "https://api.perplexity.ai/models")!
13
13
 
14
14
  static func fetchModels(apiKey: String) async throws -> PerplexityModelsResponse {
@@ -57,7 +57,7 @@ extension PerplexityModelsResponse {
57
57
  }
58
58
  }
59
59
 
60
- enum PerplexityAPIError: LocalizedError, Sendable {
60
+ enum PerplexityAPIError: LocalizedError {
61
61
  case invalidResponse
62
62
  case httpError(statusCode: Int, body: String?)
63
63
 
@@ -170,8 +170,8 @@ public struct ProviderFetchPipeline: Sendable {
170
170
 
171
171
  public init(
172
172
  resolveStrategies: @escaping @Sendable (ProviderFetchContext) async -> [any ProviderFetchStrategy],
173
- strategyTimeout: TimeInterval = 45
174
- ) {
173
+ strategyTimeout: TimeInterval = 45)
174
+ {
175
175
  self.resolveStrategies = resolveStrategies
176
176
  self.strategyTimeout = strategyTimeout
177
177
  }
@@ -472,11 +472,11 @@ public enum ProviderTokenResolver {
472
472
  if dataProtection {
473
473
  query[kSecUseDataProtectionKeychain as String] = true
474
474
  }
475
- #if canImport(LocalAuthentication)
475
+ #if canImport(LocalAuthentication)
476
476
  let authContext = LAContext()
477
477
  authContext.interactionNotAllowed = true
478
478
  query[kSecUseAuthenticationContext as String] = authContext
479
- #endif
479
+ #endif
480
480
 
481
481
  let status = SecItemCopyMatching(query as CFDictionary, &result)
482
482
  if status == errSecItemNotFound || status == errSecInteractionNotAllowed {
@@ -1,5 +1,5 @@
1
- import RunicMacroSupport
2
1
  import Foundation
2
+ import RunicMacroSupport
3
3
 
4
4
  @ProviderDescriptorRegistration
5
5
  @ProviderDescriptorDefinition
@@ -33,7 +33,9 @@ public enum QwenProviderDescriptor {
33
33
  color: ProviderColor(red: 1.0, green: 0.416, blue: 0.0)),
34
34
  tokenCost: ProviderTokenCostConfig(
35
35
  supportsTokenCost: false,
36
- noDataMessage: { "Qwen cost estimates are shown per-model in the details submenu (based on public DashScope pricing)." }),
36
+ noDataMessage: {
37
+ "Qwen cost estimates are shown per-model in the details submenu (based on public DashScope pricing)."
38
+ }),
37
39
  fetchPlan: ProviderFetchPlan(
38
40
  sourceModes: [.auto, .cli],
39
41
  pipeline: ProviderFetchPipeline(resolveStrategies: { _ in [QwenAPIFetchStrategy()] })),
@@ -71,7 +73,7 @@ struct QwenAPIFetchStrategy: ProviderFetchStrategy {
71
73
  }
72
74
  }
73
75
 
74
- enum QwenSettingsError: LocalizedError, Sendable {
76
+ enum QwenSettingsError: LocalizedError {
75
77
  case missingToken
76
78
 
77
79
  var errorDescription: String? {
@@ -46,10 +46,10 @@ public enum QwenModelPricing {
46
46
  "qwen-turbo-latest": Tier(inputPerMillion: 0.30, outputPerMillion: 0.60, contextWindow: 131_072),
47
47
  "qwen-plus": Tier(inputPerMillion: 0.80, outputPerMillion: 2.00, contextWindow: 131_072),
48
48
  "qwen-plus-latest": Tier(inputPerMillion: 0.80, outputPerMillion: 2.00, contextWindow: 131_072),
49
- "qwen-max": Tier(inputPerMillion: 2.40, outputPerMillion: 9.60, contextWindow: 32_768),
50
- "qwen-max-latest": Tier(inputPerMillion: 2.40, outputPerMillion: 9.60, contextWindow: 32_768),
51
- "qwen-vl-max": Tier(inputPerMillion: 3.00, outputPerMillion: 9.60, contextWindow: 32_768),
52
- "qwen-vl-max-latest": Tier(inputPerMillion: 3.00, outputPerMillion: 9.60, contextWindow: 32_768),
49
+ "qwen-max": Tier(inputPerMillion: 2.40, outputPerMillion: 9.60, contextWindow: 32768),
50
+ "qwen-max-latest": Tier(inputPerMillion: 2.40, outputPerMillion: 9.60, contextWindow: 32768),
51
+ "qwen-vl-max": Tier(inputPerMillion: 3.00, outputPerMillion: 9.60, contextWindow: 32768),
52
+ "qwen-vl-max-latest": Tier(inputPerMillion: 3.00, outputPerMillion: 9.60, contextWindow: 32768),
53
53
  "qwen-vl-plus": Tier(inputPerMillion: 0.80, outputPerMillion: 2.00, contextWindow: 131_072),
54
54
  "qwen-long": Tier(inputPerMillion: 0.50, outputPerMillion: 2.00, contextWindow: 10_000_000),
55
55
  "qwen2.5-72b-instruct": Tier(inputPerMillion: 0.56, outputPerMillion: 1.12, contextWindow: 131_072),
@@ -185,11 +185,25 @@ private struct QwenModelUsageRaw: Decodable {
185
185
  let requests: Int?
186
186
  let calls: Int?
187
187
 
188
- var resolvedModelID: String? { self.model_id ?? self.model }
189
- var resolvedInputTokens: Int { self.input_tokens ?? 0 }
190
- var resolvedOutputTokens: Int { self.output_tokens ?? 0 }
191
- var resolvedTotalTokens: Int { self.total_tokens ?? self.tokens ?? (self.resolvedInputTokens + self.resolvedOutputTokens) }
192
- var resolvedRequestCount: Int { self.request_count ?? self.requests ?? self.calls ?? 0 }
188
+ var resolvedModelID: String? {
189
+ self.model_id ?? self.model
190
+ }
191
+
192
+ var resolvedInputTokens: Int {
193
+ self.input_tokens ?? 0
194
+ }
195
+
196
+ var resolvedOutputTokens: Int {
197
+ self.output_tokens ?? 0
198
+ }
199
+
200
+ var resolvedTotalTokens: Int {
201
+ self.total_tokens ?? self.tokens ?? (self.resolvedInputTokens + self.resolvedOutputTokens)
202
+ }
203
+
204
+ var resolvedRequestCount: Int {
205
+ self.request_count ?? self.requests ?? self.calls ?? 0
206
+ }
193
207
  }
194
208
 
195
209
  // MARK: - Fetcher
@@ -241,11 +255,10 @@ public struct QwenUsageFetcher: Sendable {
241
255
  let output = model.resolvedOutputTokens
242
256
  let tokens = model.resolvedTotalTokens
243
257
  let requests = model.resolvedRequestCount
244
- let cost: Double?
245
- if input > 0 || output > 0 {
246
- cost = QwenModelPricing.estimateCost(inputTokens: input, outputTokens: output, modelID: modelID)
258
+ let cost: Double? = if input > 0 || output > 0 {
259
+ QwenModelPricing.estimateCost(inputTokens: input, outputTokens: output, modelID: modelID)
247
260
  } else {
248
- cost = QwenModelPricing.estimateCost(tokens: tokens, modelID: modelID)
261
+ QwenModelPricing.estimateCost(tokens: tokens, modelID: modelID)
249
262
  }
250
263
  entries.append(QwenModelUsageEntry(
251
264
  modelID: modelID,
@@ -1,5 +1,5 @@
1
- import RunicMacroSupport
2
1
  import Foundation
2
+ import RunicMacroSupport
3
3
 
4
4
  @ProviderDescriptorRegistration
5
5
  @ProviderDescriptorDefinition
@@ -71,7 +71,7 @@ struct SambaNovaAPIFetchStrategy: ProviderFetchStrategy {
71
71
  }
72
72
  }
73
73
 
74
- enum SambaNovaSettingsError: LocalizedError, Sendable {
74
+ enum SambaNovaSettingsError: LocalizedError {
75
75
  case missingToken
76
76
 
77
77
  var errorDescription: String? {
@@ -8,7 +8,7 @@ struct SambaNovaModelsResponse: Decodable {
8
8
  }
9
9
  }
10
10
 
11
- struct SambaNovaUsageFetcher {
11
+ enum SambaNovaUsageFetcher {
12
12
  static let apiURL = URL(string: "https://api.sambanova.ai/v1/models")!
13
13
 
14
14
  static func fetchModels(apiKey: String) async throws -> SambaNovaModelsResponse {
@@ -57,7 +57,7 @@ extension SambaNovaModelsResponse {
57
57
  }
58
58
  }
59
59
 
60
- enum SambaNovaAPIError: LocalizedError, Sendable {
60
+ enum SambaNovaAPIError: LocalizedError {
61
61
  case invalidResponse
62
62
  case httpError(statusCode: Int, body: String?)
63
63
 
@@ -1,5 +1,5 @@
1
- import RunicMacroSupport
2
1
  import Foundation
2
+ import RunicMacroSupport
3
3
 
4
4
  @ProviderDescriptorRegistration
5
5
  @ProviderDescriptorDefinition
@@ -71,7 +71,7 @@ struct TogetherAPIFetchStrategy: ProviderFetchStrategy {
71
71
  }
72
72
  }
73
73
 
74
- enum TogetherSettingsError: LocalizedError, Sendable {
74
+ enum TogetherSettingsError: LocalizedError {
75
75
  case missingToken
76
76
 
77
77
  var errorDescription: String? {
@@ -8,7 +8,7 @@ struct TogetherModelsResponse: Decodable {
8
8
  }
9
9
  }
10
10
 
11
- struct TogetherUsageFetcher {
11
+ enum TogetherUsageFetcher {
12
12
  static let apiURL = URL(string: "https://api.together.xyz/v1/models")!
13
13
 
14
14
  static func fetchModels(apiKey: String) async throws -> TogetherModelsResponse {
@@ -57,7 +57,7 @@ extension TogetherModelsResponse {
57
57
  }
58
58
  }
59
59
 
60
- enum TogetherAPIError: LocalizedError, Sendable {
60
+ enum TogetherAPIError: LocalizedError {
61
61
  case invalidResponse
62
62
  case httpError(statusCode: Int, body: String?)
63
63
 
@@ -1,5 +1,5 @@
1
- import RunicMacroSupport
2
1
  import Foundation
2
+ import RunicMacroSupport
3
3
 
4
4
  @ProviderDescriptorRegistration
5
5
  @ProviderDescriptorDefinition
@@ -75,7 +75,7 @@ struct VertexAICLIFetchStrategy: ProviderFetchStrategy {
75
75
  }
76
76
 
77
77
  private static func resolveProject(context: ProviderFetchContext) -> String? {
78
- if let project = Self.cleaned(context.settings?.vertexai?.project) {
78
+ if let project = cleaned(context.settings?.vertexai?.project) {
79
79
  return project
80
80
  }
81
81
  if let project = Self.cleaned(context.env["VERTEX_AI_PROJECT"]) {
@@ -91,7 +91,7 @@ struct VertexAICLIFetchStrategy: ProviderFetchStrategy {
91
91
  }
92
92
 
93
93
  private static func resolveLocation(context: ProviderFetchContext) -> String? {
94
- if let location = Self.cleaned(context.settings?.vertexai?.location) {
94
+ if let location = cleaned(context.settings?.vertexai?.location) {
95
95
  return location
96
96
  }
97
97
  if let location = Self.cleaned(context.env["VERTEX_AI_LOCATION"]) {
@@ -110,13 +110,13 @@ struct VertexAICLIFetchStrategy: ProviderFetchStrategy {
110
110
  }
111
111
  }
112
112
 
113
- enum VertexAISettingsError: LocalizedError, Sendable {
113
+ enum VertexAISettingsError: LocalizedError {
114
114
  case missingProject
115
115
 
116
116
  var errorDescription: String? {
117
117
  switch self {
118
118
  case .missingProject:
119
- return "Google Cloud project not found. Set it in Preferences \u{2192} Providers \u{2192} Vertex AI or " +
119
+ "Google Cloud project not found. Set it in Preferences \u{2192} Providers \u{2192} Vertex AI or " +
120
120
  "export VERTEX_AI_PROJECT."
121
121
  }
122
122
  }
@@ -27,7 +27,7 @@ public struct VertexAISettingsReader: Sendable {
27
27
  public static func credentials(
28
28
  environment: [String: String] = ProcessInfo.processInfo.environment) -> String?
29
29
  {
30
- self.cleaned(environment[credentialsKey])
30
+ self.cleaned(environment[self.credentialsKey])
31
31
  }
32
32
 
33
33
  static func cleaned(_ raw: String?) -> String? {
@@ -1,7 +1,7 @@
1
1
  import Foundation
2
2
 
3
- struct VertexAIModelsResponse: Decodable, Sendable {
4
- struct Model: Decodable, Sendable {
3
+ struct VertexAIModelsResponse: Decodable {
4
+ struct Model: Decodable {
5
5
  let name: String?
6
6
  let displayName: String?
7
7
  }
@@ -117,7 +117,7 @@ extension VertexAIModelsResponse {
117
117
  }
118
118
  }
119
119
 
120
- enum VertexAICLIError: LocalizedError, Sendable {
120
+ enum VertexAICLIError: LocalizedError {
121
121
  case gcloudNotFound
122
122
  case commandFailed(statusCode: Int, detail: String?)
123
123
  case commandTimedOut
@@ -1,5 +1,5 @@
1
- import RunicMacroSupport
2
1
  import Foundation
2
+ import RunicMacroSupport
3
3
 
4
4
  @ProviderDescriptorRegistration
5
5
  @ProviderDescriptorDefinition
@@ -71,7 +71,7 @@ struct XAIApiFetchStrategy: ProviderFetchStrategy {
71
71
  }
72
72
  }
73
73
 
74
- enum XAISettingsError: LocalizedError, Sendable {
74
+ enum XAISettingsError: LocalizedError {
75
75
  case missingToken
76
76
 
77
77
  var errorDescription: String? {
@@ -8,7 +8,7 @@ struct XAIModelsResponse: Decodable {
8
8
  }
9
9
  }
10
10
 
11
- struct XAIUsageFetcher {
11
+ enum XAIUsageFetcher {
12
12
  static let apiURL = URL(string: "https://api.x.ai/v1/models")!
13
13
 
14
14
  static func fetchModels(apiKey: String) async throws -> XAIModelsResponse {
@@ -57,7 +57,7 @@ extension XAIModelsResponse {
57
57
  }
58
58
  }
59
59
 
60
- enum XAIApiError: LocalizedError, Sendable {
60
+ enum XAIApiError: LocalizedError {
61
61
  case invalidResponse
62
62
  case httpError(statusCode: Int, body: String?)
63
63
 
@@ -1,5 +1,5 @@
1
- import RunicMacroSupport
2
1
  import Foundation
2
+ import RunicMacroSupport
3
3
 
4
4
  @ProviderDescriptorRegistration
5
5
  @ProviderDescriptorDefinition
@@ -33,7 +33,9 @@ public enum ZaiProviderDescriptor {
33
33
  color: ProviderColor(red: 232 / 255, green: 90 / 255, blue: 106 / 255)),
34
34
  tokenCost: ProviderTokenCostConfig(
35
35
  supportsTokenCost: false,
36
- noDataMessage: { "z.ai cost estimates are shown per-model in the details submenu (based on public API pricing)." }),
36
+ noDataMessage: {
37
+ "z.ai cost estimates are shown per-model in the details submenu (based on public API pricing)."
38
+ }),
37
39
  fetchPlan: ProviderFetchPlan(
38
40
  sourceModes: [.auto, .cli],
39
41
  pipeline: ProviderFetchPipeline(resolveStrategies: { _ in [ZaiAPIFetchStrategy()] })),