@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
@@ -26,8 +26,8 @@ public struct Team: Codable, Sendable, Identifiable {
26
26
  totalQuota: Int,
27
27
  members: [TeamMembership] = [],
28
28
  createdAt: Date = Date(),
29
- updatedAt: Date = Date()
30
- ) {
29
+ updatedAt: Date = Date())
30
+ {
31
31
  self.id = id
32
32
  self.name = name
33
33
  self.ownerUserID = ownerUserID
@@ -41,22 +41,22 @@ public struct Team: Codable, Sendable, Identifiable {
41
41
  extension Team {
42
42
  /// Total number of team members including owner
43
43
  public var memberCount: Int {
44
- return members.count
44
+ self.members.count
45
45
  }
46
46
 
47
47
  /// Get all admin users (owner + admins)
48
48
  public var adminUserIDs: [String] {
49
- return members.filter { $0.role == .owner || $0.role == .admin }.map(\.userID)
49
+ self.members.filter { $0.role == .owner || $0.role == .admin }.map(\.userID)
50
50
  }
51
51
 
52
52
  /// Check if a user is a member of this team
53
53
  public func hasMember(userID: String) -> Bool {
54
- return members.contains { $0.userID == userID }
54
+ self.members.contains { $0.userID == userID }
55
55
  }
56
56
 
57
57
  /// Get membership for a specific user
58
58
  public func membership(for userID: String) -> TeamMembership? {
59
- return members.first { $0.userID == userID }
59
+ self.members.first { $0.userID == userID }
60
60
  }
61
61
 
62
62
  /// Check if user has admin privileges
@@ -67,12 +67,12 @@ extension Team {
67
67
 
68
68
  /// Calculate total quota allocated to members with individual limits
69
69
  public var allocatedQuota: Int {
70
- return members.compactMap(\.quotaLimit).reduce(0, +)
70
+ self.members.compactMap(\.quotaLimit).reduce(0, +)
71
71
  }
72
72
 
73
73
  /// Remaining unallocated quota
74
74
  public var unallocatedQuota: Int {
75
- return max(0, totalQuota - allocatedQuota)
75
+ max(0, self.totalQuota - self.allocatedQuota)
76
76
  }
77
77
  }
78
78
 
@@ -93,8 +93,8 @@ public struct TeamMembership: Codable, Sendable, Identifiable {
93
93
  teamID: String,
94
94
  role: TeamRole,
95
95
  quotaLimit: Int? = nil,
96
- joinedAt: Date = Date()
97
- ) {
96
+ joinedAt: Date = Date())
97
+ {
98
98
  self.id = id
99
99
  self.userID = userID
100
100
  self.teamID = teamID
@@ -107,27 +107,27 @@ public struct TeamMembership: Codable, Sendable, Identifiable {
107
107
  extension TeamMembership {
108
108
  /// Check if this member can manage other members
109
109
  public var canManageMembers: Bool {
110
- return role == .owner || role == .admin
110
+ self.role == .owner || self.role == .admin
111
111
  }
112
112
 
113
113
  /// Check if this member can modify team settings
114
114
  public var canModifyTeamSettings: Bool {
115
- return role == .owner || role == .admin
115
+ self.role == .owner || self.role == .admin
116
116
  }
117
117
 
118
118
  /// Check if this member can invite others
119
119
  public var canInviteMembers: Bool {
120
- return role == .owner || role == .admin
120
+ self.role == .owner || self.role == .admin
121
121
  }
122
122
 
123
123
  /// Check if this member can view usage
124
124
  public var canViewUsage: Bool {
125
- return true // All members can view usage
125
+ true // All members can view usage
126
126
  }
127
127
 
128
128
  /// Check if this member can create projects
129
129
  public var canCreateProjects: Bool {
130
- return role != .viewer
130
+ self.role != .viewer
131
131
  }
132
132
  }
133
133
 
@@ -135,18 +135,18 @@ extension TeamMembership {
135
135
 
136
136
  /// Defines permission levels within a team
137
137
  public enum TeamRole: String, Codable, Sendable, CaseIterable {
138
- case owner = "owner"
139
- case admin = "admin"
140
- case member = "member"
141
- case viewer = "viewer"
138
+ case owner
139
+ case admin
140
+ case member
141
+ case viewer
142
142
 
143
143
  /// Display name for the role
144
144
  public var displayName: String {
145
145
  switch self {
146
- case .owner: return "Owner"
147
- case .admin: return "Admin"
148
- case .member: return "Member"
149
- case .viewer: return "Viewer"
146
+ case .owner: "Owner"
147
+ case .admin: "Admin"
148
+ case .member: "Member"
149
+ case .viewer: "Viewer"
150
150
  }
151
151
  }
152
152
 
@@ -154,29 +154,29 @@ public enum TeamRole: String, Codable, Sendable, CaseIterable {
154
154
  public var description: String {
155
155
  switch self {
156
156
  case .owner:
157
- return "Full control over team, billing, and members"
157
+ "Full control over team, billing, and members"
158
158
  case .admin:
159
- return "Can manage members and team settings"
159
+ "Can manage members and team settings"
160
160
  case .member:
161
- return "Can create and share projects within team"
161
+ "Can create and share projects within team"
162
162
  case .viewer:
163
- return "Read-only access to team projects"
163
+ "Read-only access to team projects"
164
164
  }
165
165
  }
166
166
 
167
167
  /// Permission level (higher = more permissions)
168
168
  public var level: Int {
169
169
  switch self {
170
- case .owner: return 4
171
- case .admin: return 3
172
- case .member: return 2
173
- case .viewer: return 1
170
+ case .owner: 4
171
+ case .admin: 3
172
+ case .member: 2
173
+ case .viewer: 1
174
174
  }
175
175
  }
176
176
 
177
177
  /// Check if this role can modify another role
178
178
  public func canModify(_ other: TeamRole) -> Bool {
179
- return self.level > other.level
179
+ self.level > other.level
180
180
  }
181
181
  }
182
182
 
@@ -199,8 +199,8 @@ public struct ProjectOwnership: Codable, Sendable, Identifiable {
199
199
  ownerUserID: String,
200
200
  sharedWith: [String] = [],
201
201
  accessLevel: AccessLevel = .privateAccess,
202
- createdAt: Date = Date()
203
- ) {
202
+ createdAt: Date = Date())
203
+ {
204
204
  self.id = id
205
205
  self.projectID = projectID
206
206
  self.teamID = teamID
@@ -215,17 +215,17 @@ extension ProjectOwnership {
215
215
  /// Check if a user has access to this project
216
216
  public func hasAccess(userID: String) -> Bool {
217
217
  // Owner always has access
218
- if userID == ownerUserID {
218
+ if userID == self.ownerUserID {
219
219
  return true
220
220
  }
221
221
 
222
222
  // Check access level
223
- switch accessLevel {
223
+ switch self.accessLevel {
224
224
  case .privateAccess:
225
- return sharedWith.contains(userID)
225
+ return self.sharedWith.contains(userID)
226
226
  case .team:
227
227
  // User must be in the team
228
- return teamID != nil
228
+ return self.teamID != nil
229
229
  case .public:
230
230
  return true
231
231
  }
@@ -233,24 +233,24 @@ extension ProjectOwnership {
233
233
 
234
234
  /// Check if a user can edit this project
235
235
  public func canEdit(userID: String) -> Bool {
236
- return userID == ownerUserID || sharedWith.contains(userID)
236
+ userID == self.ownerUserID || self.sharedWith.contains(userID)
237
237
  }
238
238
 
239
239
  /// Add a user to the shared list
240
240
  public mutating func share(with userID: String) {
241
- if !sharedWith.contains(userID) {
242
- sharedWith.append(userID)
241
+ if !self.sharedWith.contains(userID) {
242
+ self.sharedWith.append(userID)
243
243
  }
244
244
  }
245
245
 
246
246
  /// Remove a user from the shared list
247
247
  public mutating func unshare(with userID: String) {
248
- sharedWith.removeAll { $0 == userID }
248
+ self.sharedWith.removeAll { $0 == userID }
249
249
  }
250
250
 
251
251
  /// Check if project is owned by a team
252
252
  public var isTeamOwned: Bool {
253
- return teamID != nil
253
+ self.teamID != nil
254
254
  }
255
255
  }
256
256
 
@@ -259,24 +259,24 @@ extension ProjectOwnership {
259
259
  /// Defines who can access a project
260
260
  public enum AccessLevel: String, Codable, Sendable, CaseIterable {
261
261
  case privateAccess = "private" // Only owner and explicitly shared users
262
- case team = "team" // All team members
263
- case `public` = "public" // Anyone with link
262
+ case team // All team members
263
+ case `public` // Anyone with link
264
264
 
265
265
  /// Display name for the access level
266
266
  public var displayName: String {
267
267
  switch self {
268
- case .privateAccess: return "Private"
269
- case .team: return "Team"
270
- case .public: return "Public"
268
+ case .privateAccess: "Private"
269
+ case .team: "Team"
270
+ case .public: "Public"
271
271
  }
272
272
  }
273
273
 
274
274
  /// Icon representing the access level
275
275
  public var icon: String {
276
276
  switch self {
277
- case .privateAccess: return "lock.fill"
278
- case .team: return "person.2.fill"
279
- case .public: return "globe"
277
+ case .privateAccess: "lock.fill"
278
+ case .team: "person.2.fill"
279
+ case .public: "globe"
280
280
  }
281
281
  }
282
282
 
@@ -284,11 +284,11 @@ public enum AccessLevel: String, Codable, Sendable, CaseIterable {
284
284
  public var description: String {
285
285
  switch self {
286
286
  case .privateAccess:
287
- return "Only you and people you share with"
287
+ "Only you and people you share with"
288
288
  case .team:
289
- return "All team members can access"
289
+ "All team members can access"
290
290
  case .public:
291
- return "Anyone with the link can view"
291
+ "Anyone with the link can view"
292
292
  }
293
293
  }
294
294
  }
@@ -310,8 +310,8 @@ public struct TeamUsageSummary: Codable, Sendable {
310
310
  totalTokens: Int = 0,
311
311
  totalCost: Double = 0.0,
312
312
  memberUsage: [String: MemberUsage] = [:],
313
- quotaUsedPercent: Double = 0.0
314
- ) {
313
+ quotaUsedPercent: Double = 0.0)
314
+ {
315
315
  self.teamID = teamID
316
316
  self.period = period
317
317
  self.totalTokens = totalTokens
@@ -324,12 +324,12 @@ public struct TeamUsageSummary: Codable, Sendable {
324
324
  extension TeamUsageSummary {
325
325
  /// Get usage for a specific member
326
326
  public func usage(for userID: String) -> MemberUsage? {
327
- return memberUsage[userID]
327
+ self.memberUsage[userID]
328
328
  }
329
329
 
330
330
  /// Top users by token consumption
331
331
  public func topUsers(limit: Int = 5) -> [(userID: String, usage: MemberUsage)] {
332
- return memberUsage
332
+ self.memberUsage
333
333
  .sorted { $0.value.tokens > $1.value.tokens }
334
334
  .prefix(limit)
335
335
  .map { ($0.key, $0.value) }
@@ -337,36 +337,36 @@ extension TeamUsageSummary {
337
337
 
338
338
  /// Average tokens per member
339
339
  public var averageTokensPerMember: Int {
340
- guard !memberUsage.isEmpty else { return 0 }
341
- return totalTokens / memberUsage.count
340
+ guard !self.memberUsage.isEmpty else { return 0 }
341
+ return self.totalTokens / self.memberUsage.count
342
342
  }
343
343
 
344
344
  /// Average cost per member
345
345
  public var averageCostPerMember: Double {
346
- guard !memberUsage.isEmpty else { return 0.0 }
347
- return totalCost / Double(memberUsage.count)
346
+ guard !self.memberUsage.isEmpty else { return 0.0 }
347
+ return self.totalCost / Double(self.memberUsage.count)
348
348
  }
349
349
 
350
350
  /// Check if team is approaching quota limit
351
351
  public var isApproachingQuota: Bool {
352
- return quotaUsedPercent >= 80.0
352
+ self.quotaUsedPercent >= 80.0
353
353
  }
354
354
 
355
355
  /// Check if team has exceeded quota
356
356
  public var hasExceededQuota: Bool {
357
- return quotaUsedPercent >= 100.0
357
+ self.quotaUsedPercent >= 100.0
358
358
  }
359
359
 
360
360
  /// Add or update member usage
361
361
  public mutating func updateUsage(for userID: String, usage: MemberUsage) {
362
- memberUsage[userID] = usage
363
- recalculateTotals()
362
+ self.memberUsage[userID] = usage
363
+ self.recalculateTotals()
364
364
  }
365
365
 
366
366
  /// Recalculate total tokens and cost from member usage
367
367
  private mutating func recalculateTotals() {
368
- totalTokens = memberUsage.values.reduce(0) { $0 + $1.tokens }
369
- totalCost = memberUsage.values.reduce(0.0) { $0 + $1.cost }
368
+ self.totalTokens = self.memberUsage.values.reduce(0) { $0 + $1.tokens }
369
+ self.totalCost = self.memberUsage.values.reduce(0.0) { $0 + $1.cost }
370
370
  }
371
371
  }
372
372
 
@@ -383,8 +383,8 @@ public struct MemberUsage: Codable, Sendable {
383
383
  userID: String,
384
384
  tokens: Int = 0,
385
385
  cost: Double = 0.0,
386
- requests: Int = 0
387
- ) {
386
+ requests: Int = 0)
387
+ {
388
388
  self.userID = userID
389
389
  self.tokens = tokens
390
390
  self.cost = cost
@@ -395,20 +395,20 @@ public struct MemberUsage: Codable, Sendable {
395
395
  extension MemberUsage {
396
396
  /// Average cost per request
397
397
  public var averageCostPerRequest: Double {
398
- guard requests > 0 else { return 0.0 }
399
- return cost / Double(requests)
398
+ guard self.requests > 0 else { return 0.0 }
399
+ return self.cost / Double(self.requests)
400
400
  }
401
401
 
402
402
  /// Average tokens per request
403
403
  public var averageTokensPerRequest: Int {
404
- guard requests > 0 else { return 0 }
405
- return tokens / requests
404
+ guard self.requests > 0 else { return 0 }
405
+ return self.tokens / self.requests
406
406
  }
407
407
 
408
408
  /// Check if member has quota limit and percentage used
409
409
  public func quotaUsedPercent(limit: Int?) -> Double? {
410
- guard let limit = limit, limit > 0 else { return nil }
411
- return (Double(tokens) / Double(limit)) * 100.0
410
+ guard let limit, limit > 0 else { return nil }
411
+ return (Double(self.tokens) / Double(limit)) * 100.0
412
412
  }
413
413
 
414
414
  /// Combine with another usage record
@@ -440,8 +440,8 @@ public struct TeamInvitation: Codable, Sendable, Identifiable {
440
440
  role: TeamRole = .member,
441
441
  expiresAt: Date = Date().addingTimeInterval(7 * 24 * 60 * 60), // 7 days
442
442
  status: InvitationStatus = .pending,
443
- createdAt: Date = Date()
444
- ) {
443
+ createdAt: Date = Date())
444
+ {
445
445
  self.id = id
446
446
  self.teamID = teamID
447
447
  self.invitedEmail = invitedEmail
@@ -456,36 +456,36 @@ public struct TeamInvitation: Codable, Sendable, Identifiable {
456
456
  extension TeamInvitation {
457
457
  /// Check if invitation is still valid
458
458
  public var isValid: Bool {
459
- return status == .pending && !isExpired
459
+ self.status == .pending && !self.isExpired
460
460
  }
461
461
 
462
462
  /// Check if invitation has expired
463
463
  public var isExpired: Bool {
464
- return Date() > expiresAt
464
+ Date() > self.expiresAt
465
465
  }
466
466
 
467
467
  /// Days until expiration
468
468
  public var daysUntilExpiration: Int {
469
- let timeInterval = expiresAt.timeIntervalSince(Date())
469
+ let timeInterval = self.expiresAt.timeIntervalSince(Date())
470
470
  return max(0, Int(timeInterval / (24 * 60 * 60)))
471
471
  }
472
472
 
473
473
  /// Accept the invitation
474
474
  public mutating func accept() {
475
- guard isValid else { return }
476
- status = .accepted
475
+ guard self.isValid else { return }
476
+ self.status = .accepted
477
477
  }
478
478
 
479
479
  /// Decline the invitation
480
480
  public mutating func decline() {
481
- guard isValid else { return }
482
- status = .declined
481
+ guard self.isValid else { return }
482
+ self.status = .declined
483
483
  }
484
484
 
485
485
  /// Mark as expired
486
486
  public mutating func expire() {
487
- if status == .pending {
488
- status = .expired
487
+ if self.status == .pending {
488
+ self.status = .expired
489
489
  }
490
490
  }
491
491
  }
@@ -494,38 +494,38 @@ extension TeamInvitation {
494
494
 
495
495
  /// Status of a team invitation
496
496
  public enum InvitationStatus: String, Codable, Sendable, CaseIterable {
497
- case pending = "pending"
498
- case accepted = "accepted"
499
- case declined = "declined"
500
- case expired = "expired"
497
+ case pending
498
+ case accepted
499
+ case declined
500
+ case expired
501
501
 
502
502
  /// Display name for the status
503
503
  public var displayName: String {
504
504
  switch self {
505
- case .pending: return "Pending"
506
- case .accepted: return "Accepted"
507
- case .declined: return "Declined"
508
- case .expired: return "Expired"
505
+ case .pending: "Pending"
506
+ case .accepted: "Accepted"
507
+ case .declined: "Declined"
508
+ case .expired: "Expired"
509
509
  }
510
510
  }
511
511
 
512
512
  /// Icon representing the status
513
513
  public var icon: String {
514
514
  switch self {
515
- case .pending: return "clock.fill"
516
- case .accepted: return "checkmark.circle.fill"
517
- case .declined: return "xmark.circle.fill"
518
- case .expired: return "hourglass.bottomhalf.filled"
515
+ case .pending: "clock.fill"
516
+ case .accepted: "checkmark.circle.fill"
517
+ case .declined: "xmark.circle.fill"
518
+ case .expired: "hourglass.bottomhalf.filled"
519
519
  }
520
520
  }
521
521
 
522
522
  /// Color associated with status
523
523
  public var colorName: String {
524
524
  switch self {
525
- case .pending: return "orange"
526
- case .accepted: return "green"
527
- case .declined: return "red"
528
- case .expired: return "gray"
525
+ case .pending: "orange"
526
+ case .accepted: "green"
527
+ case .declined: "red"
528
+ case .expired: "gray"
529
529
  }
530
530
  }
531
531
  }
@@ -545,11 +545,12 @@ public struct TeamQuotaAllocation: Sendable {
545
545
  /// Get remaining quota for a specific member
546
546
  public func remainingQuota(for userID: String) -> Int? {
547
547
  guard let membership = team.membership(for: userID),
548
- let limit = membership.quotaLimit else {
548
+ let limit = membership.quotaLimit
549
+ else {
549
550
  return nil
550
551
  }
551
552
 
552
- let used = usage.usage(for: userID)?.tokens ?? 0
553
+ let used = self.usage.usage(for: userID)?.tokens ?? 0
553
554
  return max(0, limit - used)
554
555
  }
555
556
 
@@ -557,25 +558,25 @@ public struct TeamQuotaAllocation: Sendable {
557
558
  public func canUseTokens(_ tokens: Int, userID: String) -> Bool {
558
559
  guard let remaining = remainingQuota(for: userID) else {
559
560
  // No individual limit, check team limit
560
- return usage.totalTokens + tokens <= team.totalQuota
561
+ return self.usage.totalTokens + tokens <= self.team.totalQuota
561
562
  }
562
563
  return remaining >= tokens
563
564
  }
564
565
 
565
566
  /// Get members who have exceeded their quota
566
567
  public func membersExceedingQuota() -> [TeamMembership] {
567
- return team.members.filter { membership in
568
+ self.team.members.filter { membership in
568
569
  guard let limit = membership.quotaLimit else { return false }
569
- let used = usage.usage(for: membership.userID)?.tokens ?? 0
570
+ let used = self.usage.usage(for: membership.userID)?.tokens ?? 0
570
571
  return used > limit
571
572
  }
572
573
  }
573
574
 
574
575
  /// Get members approaching their quota (>80%)
575
576
  public func membersApproachingQuota() -> [TeamMembership] {
576
- return team.members.filter { membership in
577
+ self.team.members.filter { membership in
577
578
  guard let limit = membership.quotaLimit else { return false }
578
- let used = usage.usage(for: membership.userID)?.tokens ?? 0
579
+ let used = self.usage.usage(for: membership.userID)?.tokens ?? 0
579
580
  let percent = (Double(used) / Double(limit)) * 100.0
580
581
  return percent >= 80.0 && percent < 100.0
581
582
  }