@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
@@ -2,10 +2,9 @@ import Foundation
2
2
  import Testing
3
3
  @testable import RunicCore
4
4
 
5
- @Suite
6
5
  struct CopilotVSCodeTokenReaderTests {
7
6
  @Test
8
- func extractsTokenFromSessionArrayPayload() {
7
+ func `extracts token from session array payload`() {
9
8
  let token = "ghu_abcdefghijklmnopqrstuvwxyz1234567890"
10
9
  let json = """
11
10
  [
@@ -26,7 +25,7 @@ struct CopilotVSCodeTokenReaderTests {
26
25
  }
27
26
 
28
27
  @Test
29
- func extractsTokenFromNestedObjectPayload() {
28
+ func `extracts token from nested object payload`() {
30
29
  let token = "github_pat_abcdefghijklmnopqrstuvwxyz1234567890"
31
30
  let json = """
32
31
  {
@@ -45,7 +44,7 @@ struct CopilotVSCodeTokenReaderTests {
45
44
  }
46
45
 
47
46
  @Test
48
- func ignoresShortTokenValues() {
47
+ func `ignores short token values`() {
49
48
  let json = """
50
49
  {
51
50
  "sessions": [
@@ -61,7 +60,7 @@ struct CopilotVSCodeTokenReaderTests {
61
60
  }
62
61
 
63
62
  @Test
64
- func normalizesNodeBufferSecretWrapper() {
63
+ func `normalizes node buffer secret wrapper`() {
65
64
  let raw = Data("""
66
65
  {
67
66
  "type": "Buffer",
@@ -1,12 +1,10 @@
1
1
  import Foundation
2
2
  import Testing
3
-
4
3
  @testable import RunicCore
5
4
 
6
- @Suite
7
5
  struct CostUsageDecodingTests {
8
6
  @Test
9
- func decodesDailyReportTypeFormat() throws {
7
+ func `decodes daily report type format`() throws {
10
8
  let json = """
11
9
  {
12
10
  "type": "daily",
@@ -45,7 +43,7 @@ struct CostUsageDecodingTests {
45
43
  }
46
44
 
47
45
  @Test
48
- func decodesDailyReportLegacyFormat() throws {
46
+ func `decodes daily report legacy format`() throws {
49
47
  let json = """
50
48
  {
51
49
  "daily": [
@@ -81,7 +79,7 @@ struct CostUsageDecodingTests {
81
79
  }
82
80
 
83
81
  @Test
84
- func decodesLegacyCacheTokenKeys() throws {
82
+ func `decodes legacy cache token keys`() throws {
85
83
  let json = """
86
84
  {
87
85
  "type": "daily",
@@ -109,7 +107,7 @@ struct CostUsageDecodingTests {
109
107
  }
110
108
 
111
109
  @Test
112
- func decodesDailyReportLegacyFormatWithModelMap() throws {
110
+ func `decodes daily report legacy format with model map`() throws {
113
111
  let json = """
114
112
  {
115
113
  "daily": [
@@ -143,7 +141,7 @@ struct CostUsageDecodingTests {
143
141
  }
144
142
 
145
143
  @Test
146
- func decodesDailyReportLegacyFormatWithModelMapSorted() throws {
144
+ func `decodes daily report legacy format with model map sorted`() throws {
147
145
  let json = """
148
146
  {
149
147
  "daily": [
@@ -166,7 +164,7 @@ struct CostUsageDecodingTests {
166
164
  }
167
165
 
168
166
  @Test
169
- func decodesDailyReportLegacyFormatWithEmptyModelMapAsNil() throws {
167
+ func `decodes daily report legacy format with empty model map as nil`() throws {
170
168
  let json = """
171
169
  {
172
170
  "daily": [
@@ -185,7 +183,7 @@ struct CostUsageDecodingTests {
185
183
  }
186
184
 
187
185
  @Test
188
- func decodesDailyReportLegacyFormatPrefersModelsUsedListOverModelsMap() throws {
186
+ func `decodes daily report legacy format prefers models used list over models map`() throws {
189
187
  let json = """
190
188
  {
191
189
  "daily": [
@@ -207,7 +205,7 @@ struct CostUsageDecodingTests {
207
205
  }
208
206
 
209
207
  @Test
210
- func decodesDailyReportLegacyFormatWithModelsList() throws {
208
+ func `decodes daily report legacy format with models list`() throws {
211
209
  let json = """
212
210
  {
213
211
  "daily": [
@@ -226,7 +224,7 @@ struct CostUsageDecodingTests {
226
224
  }
227
225
 
228
226
  @Test
229
- func decodesDailyReportLegacyFormatWithInvalidModelsField() throws {
227
+ func `decodes daily report legacy format with invalid models field`() throws {
230
228
  let json = """
231
229
  {
232
230
  "daily": [
@@ -245,7 +243,7 @@ struct CostUsageDecodingTests {
245
243
  }
246
244
 
247
245
  @Test
248
- func decodesMonthlyReportLegacyFormat() throws {
246
+ func `decodes monthly report legacy format`() throws {
249
247
  let json = """
250
248
  {
251
249
  "monthly": [
@@ -270,7 +268,7 @@ struct CostUsageDecodingTests {
270
268
  }
271
269
 
272
270
  @Test
273
- func selectsMostRecentSession() throws {
271
+ func `selects most recent session`() throws {
274
272
  let json = """
275
273
  {
276
274
  "type": "session",
@@ -306,7 +304,7 @@ struct CostUsageDecodingTests {
306
304
  }
307
305
 
308
306
  @Test
309
- func tokenSnapshotSelectsMostRecentDay() throws {
307
+ func `token snapshot selects most recent day`() throws {
310
308
  let json = """
311
309
  {
312
310
  "type": "daily",
@@ -339,7 +337,7 @@ struct CostUsageDecodingTests {
339
337
  }
340
338
 
341
339
  @Test
342
- func tokenSnapshotUsesSummaryTotalCostWhenAvailable() throws {
340
+ func `token snapshot uses summary total cost when available`() throws {
343
341
  let json = """
344
342
  {
345
343
  "type": "daily",
@@ -359,7 +357,7 @@ struct CostUsageDecodingTests {
359
357
  }
360
358
 
361
359
  @Test
362
- func tokenSnapshotFallsBackToSummedEntriesWhenSummaryMissing() throws {
360
+ func `token snapshot falls back to summed entries when summary missing`() throws {
363
361
  let json = """
364
362
  {
365
363
  "type": "daily",
@@ -376,7 +374,7 @@ struct CostUsageDecodingTests {
376
374
  }
377
375
 
378
376
  @Test
379
- func tokenSnapshotReturnsNilTotalWhenNoCostsPresent() throws {
377
+ func `token snapshot returns nil total when no costs present`() throws {
380
378
  let json = """
381
379
  {
382
380
  "type": "daily",
@@ -1,18 +1,16 @@
1
1
  import Testing
2
-
3
2
  @testable import RunicCore
4
3
 
5
- @Suite
6
4
  struct CostUsagePricingTests {
7
5
  @Test
8
- func normalizesCodexModelVariants() {
6
+ func `normalizes codex model variants`() {
9
7
  #expect(CostUsagePricing.normalizeCodexModel("openai/gpt-5-codex") == "gpt-5")
10
8
  #expect(CostUsagePricing.normalizeCodexModel("gpt-5.2-codex") == "gpt-5.2")
11
9
  #expect(CostUsagePricing.normalizeCodexModel("gpt-5.1-codex-max") == "gpt-5.1")
12
10
  }
13
11
 
14
12
  @Test
15
- func codexCostSupportsGpt51CodexMax() {
13
+ func `codex cost supports gpt51 codex max`() {
16
14
  let cost = CostUsagePricing.codexCostUSD(
17
15
  model: "gpt-5.1-codex-max",
18
16
  inputTokens: 100,
@@ -22,12 +20,12 @@ struct CostUsagePricingTests {
22
20
  }
23
21
 
24
22
  @Test
25
- func normalizesClaudeOpus41DatedVariants() {
23
+ func `normalizes claude opus41 dated variants`() {
26
24
  #expect(CostUsagePricing.normalizeClaudeModel("claude-opus-4-1-20250805") == "claude-opus-4-1")
27
25
  }
28
26
 
29
27
  @Test
30
- func claudeCostSupportsOpus41DatedVariant() {
28
+ func `claude cost supports opus41 dated variant`() {
31
29
  let cost = CostUsagePricing.claudeCostUSD(
32
30
  model: "claude-opus-4-1-20250805",
33
31
  inputTokens: 10,
@@ -38,7 +36,7 @@ struct CostUsagePricingTests {
38
36
  }
39
37
 
40
38
  @Test
41
- func claudeCostReturnsNilForUnknownModels() {
39
+ func `claude cost returns nil for unknown models`() {
42
40
  let cost = CostUsagePricing.claudeCostUSD(
43
41
  model: "glm-4.6",
44
42
  inputTokens: 100,
@@ -1,12 +1,10 @@
1
1
  import Foundation
2
2
  import Testing
3
-
4
3
  @testable import RunicCore
5
4
 
6
- @Suite
7
5
  struct CostUsageScannerTests {
8
6
  @Test
9
- func codexDailyReportParsesTokenCountsAndCaches() throws {
7
+ func `codex daily report parses token counts and caches`() throws {
10
8
  let env = try CostUsageTestEnvironment()
11
9
  defer { env.cleanup() }
12
10
 
@@ -91,7 +89,7 @@ struct CostUsageScannerTests {
91
89
  }
92
90
 
93
91
  @Test
94
- func claudeDailyReportParsesUsageAndCaches() throws {
92
+ func `claude daily report parses usage and caches`() throws {
95
93
  let env = try CostUsageTestEnvironment()
96
94
  defer { env.cleanup() }
97
95
 
@@ -138,7 +136,7 @@ struct CostUsageScannerTests {
138
136
  }
139
137
 
140
138
  @Test
141
- func claudeParsesLargeLinesWithUsageAtTail() throws {
139
+ func `claude parses large lines with usage at tail`() throws {
142
140
  let env = try CostUsageTestEnvironment()
143
141
  defer { env.cleanup() }
144
142
 
@@ -183,7 +181,7 @@ struct CostUsageScannerTests {
183
181
  }
184
182
 
185
183
  @Test
186
- func claudeDailyReportRefreshesWhenFileChanges() throws {
184
+ func `claude daily report refreshes when file changes`() throws {
187
185
  let env = try CostUsageTestEnvironment()
188
186
  defer { env.cleanup() }
189
187
 
@@ -248,7 +246,7 @@ struct CostUsageScannerTests {
248
246
  }
249
247
 
250
248
  @Test
251
- func codexIncrementalParsingUsesPreviousTotals() throws {
249
+ func `codex incremental parsing uses previous totals`() throws {
252
250
  let env = try CostUsageTestEnvironment()
253
251
  defer { env.cleanup() }
254
252
 
@@ -327,7 +325,7 @@ struct CostUsageScannerTests {
327
325
  }
328
326
 
329
327
  @Test
330
- func claudeIncrementalParsingReadsAppendedLinesOnly() throws {
328
+ func `claude incremental parsing reads appended lines only`() throws {
331
329
  let env = try CostUsageTestEnvironment()
332
330
  defer { env.cleanup() }
333
331
 
@@ -387,7 +385,7 @@ struct CostUsageScannerTests {
387
385
  }
388
386
 
389
387
  @Test
390
- func dayKeyFromTimestampMatchesISOParsing() {
388
+ func `day key from timestamp matches ISO parsing`() {
391
389
  let timestamps = [
392
390
  "2025-12-20T23:59:59Z",
393
391
  "2025-12-20T23:59:59+02:00",
@@ -401,7 +399,7 @@ struct CostUsageScannerTests {
401
399
  }
402
400
 
403
401
  @Test
404
- func claudeDeduplicatesStreamingChunks() throws {
402
+ func `claude deduplicates streaming chunks`() throws {
405
403
  let env = try CostUsageTestEnvironment()
406
404
  defer { env.cleanup() }
407
405
 
@@ -489,7 +487,7 @@ struct CostUsageScannerTests {
489
487
  }
490
488
 
491
489
  @Test
492
- func claudeCountsEntriesWithoutIdsAsSeparate() throws {
490
+ func `claude counts entries without ids as separate`() throws {
493
491
  let env = try CostUsageTestEnvironment()
494
492
  defer { env.cleanup() }
495
493
 
@@ -553,7 +551,7 @@ struct CostUsageScannerTests {
553
551
  }
554
552
 
555
553
  @Test
556
- func claudeCountsDifferentRequestIdsSeparately() throws {
554
+ func `claude counts different request ids separately`() throws {
557
555
  let env = try CostUsageTestEnvironment()
558
556
  defer { env.cleanup() }
559
557
 
@@ -2,12 +2,11 @@ import Foundation
2
2
  import Testing
3
3
  @testable import RunicCore
4
4
 
5
- @Suite
6
5
  struct CursorStatusProbeTests {
7
6
  // MARK: - Usage Summary Parsing
8
7
 
9
8
  @Test
10
- func parsesBasicUsageSummary() throws {
9
+ func `parses basic usage summary`() throws {
11
10
  let json = """
12
11
  {
13
12
  "billingCycleStart": "2025-01-01T00:00:00.000Z",
@@ -38,7 +37,7 @@ struct CursorStatusProbeTests {
38
37
  }
39
38
  }
40
39
  """
41
- let data = json.data(using: .utf8)!
40
+ let data = try #require(json.data(using: .utf8))
42
41
  let summary = try JSONDecoder().decode(CursorUsageSummary.self, from: data)
43
42
 
44
43
  #expect(summary.membershipType == "pro")
@@ -51,7 +50,7 @@ struct CursorStatusProbeTests {
51
50
  }
52
51
 
53
52
  @Test
54
- func parsesMinimalUsageSummary() throws {
53
+ func `parses minimal usage summary`() throws {
55
54
  let json = """
56
55
  {
57
56
  "membershipType": "hobby",
@@ -63,7 +62,7 @@ struct CursorStatusProbeTests {
63
62
  }
64
63
  }
65
64
  """
66
- let data = json.data(using: .utf8)!
65
+ let data = try #require(json.data(using: .utf8))
67
66
  let summary = try JSONDecoder().decode(CursorUsageSummary.self, from: data)
68
67
 
69
68
  #expect(summary.membershipType == "hobby")
@@ -73,7 +72,7 @@ struct CursorStatusProbeTests {
73
72
  }
74
73
 
75
74
  @Test
76
- func parsesEnterpriseUsageSummary() throws {
75
+ func `parses enterprise usage summary`() throws {
77
76
  let json = """
78
77
  {
79
78
  "membershipType": "enterprise",
@@ -88,7 +87,7 @@ struct CursorStatusProbeTests {
88
87
  }
89
88
  }
90
89
  """
91
- let data = json.data(using: .utf8)!
90
+ let data = try #require(json.data(using: .utf8))
92
91
  let summary = try JSONDecoder().decode(CursorUsageSummary.self, from: data)
93
92
 
94
93
  #expect(summary.membershipType == "enterprise")
@@ -99,7 +98,7 @@ struct CursorStatusProbeTests {
99
98
  // MARK: - User Info Parsing
100
99
 
101
100
  @Test
102
- func parsesUserInfo() throws {
101
+ func `parses user info`() throws {
103
102
  let json = """
104
103
  {
105
104
  "email": "user@example.com",
@@ -108,7 +107,7 @@ struct CursorStatusProbeTests {
108
107
  "sub": "auth0|12345"
109
108
  }
110
109
  """
111
- let data = json.data(using: .utf8)!
110
+ let data = try #require(json.data(using: .utf8))
112
111
  let userInfo = try JSONDecoder().decode(CursorUserInfo.self, from: data)
113
112
 
114
113
  #expect(userInfo.email == "user@example.com")
@@ -120,7 +119,7 @@ struct CursorStatusProbeTests {
120
119
  // MARK: - Snapshot Conversion
121
120
 
122
121
  @Test
123
- func prefersPlanRatioOverPercentField() {
122
+ func `prefers plan ratio over percent field`() {
124
123
  let snapshot = CursorStatusProbe()
125
124
  .parseUsageSummary(
126
125
  CursorUsageSummary(
@@ -149,7 +148,7 @@ struct CursorStatusProbeTests {
149
148
  }
150
149
 
151
150
  @Test
152
- func usesPercentFieldWhenLimitMissing() {
151
+ func `uses percent field when limit missing`() {
153
152
  let snapshot = CursorStatusProbe()
154
153
  .parseUsageSummary(
155
154
  CursorUsageSummary(
@@ -178,7 +177,7 @@ struct CursorStatusProbeTests {
178
177
  }
179
178
 
180
179
  @Test
181
- func convertsSnapshotToUsageSnapshot() {
180
+ func `converts snapshot to usage snapshot`() {
182
181
  let snapshot = CursorStatusSnapshot(
183
182
  planPercentUsed: 45.0,
184
183
  planUsedUSD: 22.50,
@@ -206,7 +205,7 @@ struct CursorStatusProbeTests {
206
205
  }
207
206
 
208
207
  @Test
209
- func usesIndividualOnDemandWhenNoTeamUsage() {
208
+ func `uses individual on demand when no team usage`() {
210
209
  let snapshot = CursorStatusSnapshot(
211
210
  planPercentUsed: 10.0,
212
211
  planUsedUSD: 5.0,
@@ -229,7 +228,7 @@ struct CursorStatusProbeTests {
229
228
  }
230
229
 
231
230
  @Test
232
- func formatsMembershipTypes() {
231
+ func `formats membership types`() {
233
232
  let testCases: [(input: String, expected: String)] = [
234
233
  ("pro", "Cursor Pro"),
235
234
  ("hobby", "Cursor Hobby"),
@@ -259,7 +258,7 @@ struct CursorStatusProbeTests {
259
258
  }
260
259
 
261
260
  @Test
262
- func handlesNilOnDemandLimit() {
261
+ func `handles nil on demand limit`() {
263
262
  let snapshot = CursorStatusSnapshot(
264
263
  planPercentUsed: 50.0,
265
264
  planUsedUSD: 25.0,
@@ -287,7 +286,7 @@ struct CursorStatusProbeTests {
287
286
  // MARK: - Session Store Serialization
288
287
 
289
288
  @Test
290
- func sessionStoreSavesAndLoadsCookies() async throws {
289
+ func `session store saves and loads cookies`() async {
291
290
  let store = CursorSessionStore.shared
292
291
 
293
292
  // Clear any existing cookies
@@ -2,10 +2,9 @@ import Foundation
2
2
  import Testing
3
3
  @testable import RunicCore
4
4
 
5
- @Suite
6
5
  struct FactoryStatusSnapshotTests {
7
6
  @Test
8
- func mapsUsageSnapshotWindowsAndLoginMethod() {
7
+ func `maps usage snapshot windows and login method`() {
9
8
  let periodEnd = Date(timeIntervalSince1970: 1_738_368_000) // Feb 1, 2025
10
9
  let snapshot = FactoryStatusSnapshot(
11
10
  standardUserTokens: 50,
@@ -33,7 +32,7 @@ struct FactoryStatusSnapshotTests {
33
32
  }
34
33
 
35
34
  @Test
36
- func treatsLargeAllowancesAsUnlimited() {
35
+ func `treats large allowances as unlimited`() {
37
36
  let snapshot = FactoryStatusSnapshot(
38
37
  standardUserTokens: 50_000_000,
39
38
  standardOrgTokens: 0,
@@ -56,10 +55,9 @@ struct FactoryStatusSnapshotTests {
56
55
  }
57
56
  }
58
57
 
59
- @Suite
60
58
  struct FactoryStatusProbeWorkOSTests {
61
59
  @Test
62
- func detectsMissingRefreshTokenPayload() {
60
+ func `detects missing refresh token payload`() {
63
61
  let payload = Data("""
64
62
  {"error":"invalid_request","error_description":"Missing refresh token."}
65
63
  """.utf8)
@@ -1,10 +1,9 @@
1
1
  import Testing
2
2
  @testable import Runic
3
3
 
4
- @Suite
5
4
  struct GeminiLoginAlertTests {
6
5
  @Test
7
- func returnsAlertForMissingBinary() {
6
+ func `returns alert for missing binary`() {
8
7
  let result = GeminiLoginRunner.Result(outcome: .missingBinary)
9
8
  let info = StatusItemController.geminiLoginAlertInfo(for: result)
10
9
  #expect(info?.title == "Gemini CLI not found")
@@ -12,7 +11,7 @@ struct GeminiLoginAlertTests {
12
11
  }
13
12
 
14
13
  @Test
15
- func returnsAlertForLaunchFailure() {
14
+ func `returns alert for launch failure`() {
16
15
  let result = GeminiLoginRunner.Result(outcome: .launchFailed("Boom"))
17
16
  let info = StatusItemController.geminiLoginAlertInfo(for: result)
18
17
  #expect(info?.title == "Could not open Terminal for Gemini")
@@ -20,7 +19,7 @@ struct GeminiLoginAlertTests {
20
19
  }
21
20
 
22
21
  @Test
23
- func returnsNilOnSuccess() {
22
+ func `returns nil on success`() {
24
23
  let result = GeminiLoginRunner.Result(outcome: .success)
25
24
  let info = StatusItemController.geminiLoginAlertInfo(for: result)
26
25
  #expect(info == nil)
@@ -1,11 +1,11 @@
1
- import RunicCore
2
1
  import Foundation
2
+ import RunicCore
3
3
  import Testing
4
4
 
5
- @Suite("Gemini API", .serialized)
5
+ @Suite(.serialized)
6
6
  struct GeminiStatusProbeAPITests {
7
7
  @Test
8
- func missingCredentialsThrowsNotLoggedIn() async throws {
8
+ func `missing credentials throws not logged in`() async throws {
9
9
  let env = try GeminiTestEnvironment()
10
10
  defer { env.cleanup() }
11
11
 
@@ -16,7 +16,7 @@ struct GeminiStatusProbeAPITests {
16
16
  }
17
17
 
18
18
  @Test
19
- func rejectsApiKeyAuthType() async throws {
19
+ func `rejects api key auth type`() async throws {
20
20
  let env = try GeminiTestEnvironment()
21
21
  defer { env.cleanup() }
22
22
  try env.writeSettings(authType: "api-key")
@@ -28,7 +28,7 @@ struct GeminiStatusProbeAPITests {
28
28
  }
29
29
 
30
30
  @Test
31
- func rejectsVertexAuthType() async throws {
31
+ func `rejects vertex auth type`() async throws {
32
32
  let env = try GeminiTestEnvironment()
33
33
  defer { env.cleanup() }
34
34
  try env.writeSettings(authType: "vertex-ai")
@@ -40,7 +40,7 @@ struct GeminiStatusProbeAPITests {
40
40
  }
41
41
 
42
42
  @Test
43
- func refreshesExpiredTokenAndUpdatesStoredCredentials() async throws {
43
+ func `refreshes expired token and updates stored credentials`() async throws {
44
44
  let env = try GeminiTestEnvironment()
45
45
  defer { env.cleanup() }
46
46
  try env.writeCredentials(
@@ -112,7 +112,7 @@ struct GeminiStatusProbeAPITests {
112
112
  }
113
113
 
114
114
  @Test
115
- func failsRefreshWhenOAuthConfigMissing() async throws {
115
+ func `fails refresh when O auth config missing`() async throws {
116
116
  let env = try GeminiTestEnvironment()
117
117
  defer { env.cleanup() }
118
118
  try env.writeCredentials(
@@ -139,7 +139,7 @@ struct GeminiStatusProbeAPITests {
139
139
  }
140
140
 
141
141
  @Test
142
- func reportsApiErrors() async throws {
142
+ func `reports api errors`() async throws {
143
143
  let env = try GeminiTestEnvironment()
144
144
  defer { env.cleanup() }
145
145
  try env.writeCredentials(
@@ -175,7 +175,7 @@ struct GeminiStatusProbeAPITests {
175
175
  }
176
176
 
177
177
  @Test
178
- func reportsNotLoggedInWhenAccessTokenMissing() async throws {
178
+ func `reports not logged in when access token missing`() async throws {
179
179
  let env = try GeminiTestEnvironment()
180
180
  defer { env.cleanup() }
181
181
  try env.writeCredentials(
@@ -191,7 +191,7 @@ struct GeminiStatusProbeAPITests {
191
191
  }
192
192
 
193
193
  @Test
194
- func reportsNotLoggedInOn401() async throws {
194
+ func `reports not logged in on401`() async throws {
195
195
  let env = try GeminiTestEnvironment()
196
196
  defer { env.cleanup() }
197
197
  try env.writeCredentials(
@@ -227,7 +227,7 @@ struct GeminiStatusProbeAPITests {
227
227
  }
228
228
 
229
229
  @Test
230
- func reportsParseErrorsForInvalidPayload() async throws {
230
+ func `reports parse errors for invalid payload`() async throws {
231
231
  let env = try GeminiTestEnvironment()
232
232
  defer { env.cleanup() }
233
233
  try env.writeCredentials(
@@ -1,11 +1,11 @@
1
- import RunicCore
2
1
  import Foundation
2
+ import RunicCore
3
3
  import Testing
4
4
 
5
- @Suite("Gemini Plan", .serialized)
5
+ @Suite(.serialized)
6
6
  struct GeminiStatusProbePlanTests {
7
7
  @Test
8
- func selectsProjectIdForQuotaRequests() async throws {
8
+ func `selects project id for quota requests`() async throws {
9
9
  let env = try GeminiTestEnvironment()
10
10
  defer { env.cleanup() }
11
11
  try env.writeCredentials(
@@ -56,7 +56,7 @@ struct GeminiStatusProbePlanTests {
56
56
  }
57
57
 
58
58
  @Test
59
- func detectsPaidFromStandardTier() async throws {
59
+ func `detects paid from standard tier`() async throws {
60
60
  let env = try GeminiTestEnvironment()
61
61
  defer { env.cleanup() }
62
62
  try env.writeCredentials(
@@ -100,7 +100,7 @@ struct GeminiStatusProbePlanTests {
100
100
  }
101
101
 
102
102
  @Test
103
- func detectsWorkspaceFromFreeTierWithHostedDomain() async throws {
103
+ func `detects workspace from free tier with hosted domain`() async throws {
104
104
  let env = try GeminiTestEnvironment()
105
105
  defer { env.cleanup() }
106
106
  let idToken = GeminiAPITestHelpers.makeIDToken(email: "user@company.com", hostedDomain: "company.com")
@@ -145,7 +145,7 @@ struct GeminiStatusProbePlanTests {
145
145
  }
146
146
 
147
147
  @Test
148
- func detectsFreeFromFreeTierWithoutHostedDomain() async throws {
148
+ func `detects free from free tier without hosted domain`() async throws {
149
149
  let env = try GeminiTestEnvironment()
150
150
  defer { env.cleanup() }
151
151
  let idToken = GeminiAPITestHelpers.makeIDToken(email: "user@gmail.com")
@@ -190,7 +190,7 @@ struct GeminiStatusProbePlanTests {
190
190
  }
191
191
 
192
192
  @Test
193
- func detectsLegacyFromLegacyTier() async throws {
193
+ func `detects legacy from legacy tier`() async throws {
194
194
  let env = try GeminiTestEnvironment()
195
195
  defer { env.cleanup() }
196
196
  try env.writeCredentials(
@@ -234,7 +234,7 @@ struct GeminiStatusProbePlanTests {
234
234
  }
235
235
 
236
236
  @Test
237
- func leavesBlankWhenLoadCodeAssistFails() async throws {
237
+ func `leaves blank when load code assist fails`() async throws {
238
238
  let env = try GeminiTestEnvironment()
239
239
  defer { env.cleanup() }
240
240
  try env.writeCredentials(