@sriinnu/runic 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (348) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +1 -1
  3. package/README.md +47 -29
  4. package/RuniciOS/Core/RunicTypographyiOS.swift +24 -0
  5. package/RuniciOS/Views/ProviderDetailView.swift +9 -9
  6. package/RuniciOS/Views/ProviderListView.swift +10 -10
  7. package/RuniciOS/Widgets/LargeWidget.swift +14 -14
  8. package/RuniciOS/Widgets/LiveActivity.swift +19 -19
  9. package/RuniciOS/Widgets/LockScreenWidget.swift +15 -15
  10. package/RuniciOS/Widgets/MediumWidget.swift +10 -10
  11. package/RuniciOS/Widgets/RunicWidget.swift +5 -5
  12. package/RuniciOS/Widgets/SmallWidget.swift +9 -9
  13. package/Scripts/package_app.sh +2 -2
  14. package/Sources/Runic/About.swift +3 -3
  15. package/Sources/Runic/AppNotifications.swift +5 -3
  16. package/Sources/Runic/Controllers/StatusItemController+Actions.swift +17 -4
  17. package/Sources/Runic/Controllers/StatusItemController+Animation.swift +5 -4
  18. package/Sources/Runic/Controllers/StatusItemController+ChartSubmenus.swift +30 -16
  19. package/Sources/Runic/Controllers/StatusItemController+CustomProviders.swift +6 -3
  20. package/Sources/Runic/Controllers/StatusItemController+Menu.swift +47 -14
  21. package/Sources/Runic/Controllers/StatusItemController+MenuCards.swift +6 -4
  22. package/Sources/Runic/Controllers/StatusItemController+MenuHelpers.swift +40 -12
  23. package/Sources/Runic/Controllers/StatusItemController.swift +43 -43
  24. package/Sources/Runic/Core/BudgetNotificationManager.swift +2 -1
  25. package/Sources/Runic/Core/Login/ClaudeLoginRunner.swift +2 -2
  26. package/Sources/Runic/Core/Login/CodexLoginRunner.swift +1 -1
  27. package/Sources/Runic/Core/Login/CursorLoginRunner.swift +4 -4
  28. package/Sources/Runic/Core/Login/GeminiLoginRunner.swift +3 -6
  29. package/Sources/Runic/Core/Rendering/IconRenderer.swift +91 -85
  30. package/Sources/Runic/Core/Rendering/IconView.swift +3 -1
  31. package/Sources/Runic/Core/RunicColors.swift +6 -6
  32. package/Sources/Runic/Core/RunicSpacing.swift +7 -7
  33. package/Sources/Runic/Core/RunicTypography.swift +206 -0
  34. package/Sources/Runic/Core/Stores/AuggieTokenStore.swift +10 -36
  35. package/Sources/Runic/Core/Stores/AzureOpenAITokenStore.swift +10 -36
  36. package/Sources/Runic/Core/Stores/CerebrasTokenStore.swift +10 -36
  37. package/Sources/Runic/Core/Stores/CohereTokenStore.swift +10 -36
  38. package/Sources/Runic/Core/Stores/CopilotTokenStore.swift +10 -36
  39. package/Sources/Runic/Core/Stores/CustomProviderStore.swift +10 -10
  40. package/Sources/Runic/Core/Stores/DeepSeekTokenStore.swift +10 -36
  41. package/Sources/Runic/Core/Stores/FireworksTokenStore.swift +10 -36
  42. package/Sources/Runic/Core/Stores/GroqTokenStore.swift +10 -36
  43. package/Sources/Runic/Core/Stores/KimiTokenStore.swift +10 -36
  44. package/Sources/Runic/Core/Stores/MiniMaxCookieHeaderStore.swift +10 -36
  45. package/Sources/Runic/Core/Stores/MiniMaxGroupIDStore.swift +10 -36
  46. package/Sources/Runic/Core/Stores/MiniMaxTokenStore.swift +10 -36
  47. package/Sources/Runic/Core/Stores/MistralTokenStore.swift +10 -36
  48. package/Sources/Runic/Core/Stores/OpenRouterTokenStore.swift +10 -36
  49. package/Sources/Runic/Core/Stores/PerplexityTokenStore.swift +10 -36
  50. package/Sources/Runic/Core/Stores/ProviderToggleStore.swift +1 -1
  51. package/Sources/Runic/Core/Stores/QwenTokenStore.swift +10 -36
  52. package/Sources/Runic/Core/Stores/SambaNovaTokenStore.swift +10 -36
  53. package/Sources/Runic/Core/Stores/SettingsStore.swift +99 -52
  54. package/Sources/Runic/Core/Stores/TogetherTokenStore.swift +10 -36
  55. package/Sources/Runic/Core/Stores/UsageStore+Accessors.swift +19 -6
  56. package/Sources/Runic/Core/Stores/UsageStore+TokenCost.swift +1 -1
  57. package/Sources/Runic/Core/Stores/UsageStore+WidgetSnapshot.swift +1 -1
  58. package/Sources/Runic/Core/Stores/UsageStore.swift +234 -167
  59. package/Sources/Runic/Core/Stores/XAITokenStore.swift +10 -36
  60. package/Sources/Runic/Core/Stores/ZaiTokenStore.swift +10 -36
  61. package/Sources/Runic/Core/UsageExporter.swift +8 -4
  62. package/Sources/Runic/ProviderRegistry.swift +1 -1
  63. package/Sources/Runic/Providers/Antigravity/AntigravityProviderImplementation.swift +1 -1
  64. package/Sources/Runic/Providers/Auggie/AuggieProviderImplementation.swift +1 -1
  65. package/Sources/Runic/Providers/Azure/AzureProviderImplementation.swift +1 -1
  66. package/Sources/Runic/Providers/Bedrock/BedrockProviderImplementation.swift +1 -1
  67. package/Sources/Runic/Providers/Cerebras/CerebrasProviderImplementation.swift +1 -1
  68. package/Sources/Runic/Providers/Codex/CodexProviderImplementation.swift +1 -1
  69. package/Sources/Runic/Providers/Cohere/CohereProviderImplementation.swift +1 -1
  70. package/Sources/Runic/Providers/Cursor/CursorProviderImplementation.swift +1 -1
  71. package/Sources/Runic/Providers/DeepSeek/DeepSeekProviderImplementation.swift +1 -1
  72. package/Sources/Runic/Providers/Factory/FactoryProviderImplementation.swift +1 -1
  73. package/Sources/Runic/Providers/Fireworks/FireworksProviderImplementation.swift +1 -1
  74. package/Sources/Runic/Providers/Gemini/GeminiProviderImplementation.swift +1 -1
  75. package/Sources/Runic/Providers/Groq/GroqProviderImplementation.swift +1 -1
  76. package/Sources/Runic/Providers/Kimi/KimiProviderImplementation.swift +1 -1
  77. package/Sources/Runic/Providers/MiniMax/MiniMaxProviderImplementation.swift +1 -1
  78. package/Sources/Runic/Providers/Mistral/MistralProviderImplementation.swift +1 -1
  79. package/Sources/Runic/Providers/OpenRouter/OpenRouterProviderImplementation.swift +1 -1
  80. package/Sources/Runic/Providers/Perplexity/PerplexityProviderImplementation.swift +1 -1
  81. package/Sources/Runic/Providers/SambaNova/SambaNovaProviderImplementation.swift +1 -1
  82. package/Sources/Runic/Providers/Shared/ProviderImplementation.swift +5 -2
  83. package/Sources/Runic/Providers/Shared/ProviderImplementationRegistry.swift +1 -1
  84. package/Sources/Runic/Providers/Shared/ProviderSettingsDescriptors.swift +1 -1
  85. package/Sources/Runic/Providers/Together/TogetherProviderImplementation.swift +1 -1
  86. package/Sources/Runic/Providers/XAI/XAIProviderImplementation.swift +1 -1
  87. package/Sources/Runic/Providers/Zai/ZaiProviderImplementation.swift +1 -1
  88. package/Sources/Runic/Resources/Fonts/Caveat-Bold.ttf +0 -0
  89. package/Sources/Runic/Resources/Fonts/Caveat-Regular.ttf +0 -0
  90. package/Sources/Runic/Resources/Fonts/FiraCode-Bold.ttf +0 -0
  91. package/Sources/Runic/Resources/Fonts/FiraCode-Light.ttf +0 -0
  92. package/Sources/Runic/Resources/Fonts/FiraCode-Medium.ttf +0 -0
  93. package/Sources/Runic/Resources/Fonts/FiraCode-Regular.ttf +0 -0
  94. package/Sources/Runic/Resources/Fonts/FiraCode-SemiBold.ttf +0 -0
  95. package/Sources/Runic/Resources/Fonts/IBMPlexMono-Bold.ttf +0 -0
  96. package/Sources/Runic/Resources/Fonts/IBMPlexMono-Medium.ttf +0 -0
  97. package/Sources/Runic/Resources/Fonts/IBMPlexMono-Regular.ttf +0 -0
  98. package/Sources/Runic/Resources/Fonts/IBMPlexMono-SemiBold.ttf +0 -0
  99. package/Sources/Runic/Resources/Fonts/Inconsolata-Bold.ttf +0 -0
  100. package/Sources/Runic/Resources/Fonts/Inconsolata-Medium.ttf +0 -0
  101. package/Sources/Runic/Resources/Fonts/Inconsolata-Regular.ttf +0 -0
  102. package/Sources/Runic/Resources/Fonts/Inconsolata-SemiBold.ttf +0 -0
  103. package/Sources/Runic/Resources/Fonts/JetBrainsMono-Bold.ttf +0 -0
  104. package/Sources/Runic/Resources/Fonts/JetBrainsMono-Medium.ttf +0 -0
  105. package/Sources/Runic/Resources/Fonts/JetBrainsMono-Regular.ttf +0 -0
  106. package/Sources/Runic/Resources/Fonts/JetBrainsMono-SemiBold.ttf +0 -0
  107. package/Sources/Runic/Resources/Fonts/SpaceMono-Bold.ttf +0 -0
  108. package/Sources/Runic/Resources/Fonts/SpaceMono-Regular.ttf +0 -0
  109. package/Sources/Runic/Resources/provider-context-windows.json +20 -0
  110. package/Sources/Runic/RunicApp.swift +46 -36
  111. package/Sources/Runic/SessionQuotaNotifications.swift +2 -2
  112. package/Sources/Runic/UsagePaceText.swift +1 -1
  113. package/Sources/Runic/UsageProgressBar.swift +13 -9
  114. package/Sources/Runic/Utilities/LoadingPattern.swift +4 -2
  115. package/Sources/Runic/Utilities/PerformanceConstants.swift +28 -28
  116. package/Sources/Runic/Views/Menu/AlertsMenuView.swift +19 -21
  117. package/Sources/Runic/Views/Menu/CostComparativeChartMenuView.swift +19 -19
  118. package/Sources/Runic/Views/Menu/CostHistoryChartMenuView.swift +7 -7
  119. package/Sources/Runic/Views/Menu/CreditsHistoryChartMenuView.swift +5 -5
  120. package/Sources/Runic/Views/Menu/EfficiencyMetricsMenuView.swift +29 -30
  121. package/Sources/Runic/Views/Menu/HeroStatCardsMenuView.swift +20 -17
  122. package/Sources/Runic/Views/Menu/HourlyActivityChartMenuView.swift +14 -14
  123. package/Sources/Runic/Views/Menu/InlineUsageChartView.swift +15 -20
  124. package/Sources/Runic/Views/Menu/MenuCardEntranceModifier.swift +3 -4
  125. package/Sources/Runic/Views/Menu/MenuCardSidebarView.swift +5 -25
  126. package/Sources/Runic/Views/Menu/MenuCardSkeletonView.swift +1 -1
  127. package/Sources/Runic/Views/Menu/MenuCardView.swift +120 -131
  128. package/Sources/Runic/Views/Menu/MenuContent.swift +11 -8
  129. package/Sources/Runic/Views/Menu/MenuDescriptor.swift +4 -2
  130. package/Sources/Runic/Views/Menu/MenuHighlightStyle.swift +1 -8
  131. package/Sources/Runic/Views/Menu/ModelBreakdownMenuView.swift +20 -14
  132. package/Sources/Runic/Views/Menu/OverviewMenuView.swift +198 -58
  133. package/Sources/Runic/Views/Menu/ProjectBreakdownMenuView.swift +16 -11
  134. package/Sources/Runic/Views/Menu/ProjectBudgetMenuView.swift +27 -27
  135. package/Sources/Runic/Views/Menu/ProviderTabBarView.swift +4 -6
  136. package/Sources/Runic/Views/Menu/SubscriptionUtilizationChartMenuView.swift +24 -11
  137. package/Sources/Runic/Views/Menu/UsageBreakdownChartMenuView.swift +5 -5
  138. package/Sources/Runic/Views/Menu/UsageHeatmapMenuView.swift +7 -8
  139. package/Sources/Runic/Views/Menu/UsageTimelineChartMenuView.swift +28 -76
  140. package/Sources/Runic/Views/Menu/UsageWindowComparisonChartMenuView.swift +8 -7
  141. package/Sources/Runic/Views/Menu/WeeklyActivityChartMenuView.swift +7 -7
  142. package/Sources/Runic/Views/Performance/PerformanceDashboardView.swift +50 -47
  143. package/Sources/Runic/Views/Preferences/LiquidComponents.swift +15 -14
  144. package/Sources/Runic/Views/Preferences/PreferencesAboutPane.swift +7 -7
  145. package/Sources/Runic/Views/Preferences/PreferencesAdvancedPane.swift +27 -27
  146. package/Sources/Runic/Views/Preferences/PreferencesAlertsPane.swift +38 -42
  147. package/Sources/Runic/Views/Preferences/PreferencesAnalyticsPane.swift +39 -43
  148. package/Sources/Runic/Views/Preferences/PreferencesBudgetsPane.swift +21 -21
  149. package/Sources/Runic/Views/Preferences/PreferencesComponents.swift +7 -7
  150. package/Sources/Runic/Views/Preferences/PreferencesCustomProvidersPane.swift +49 -50
  151. package/Sources/Runic/Views/Preferences/PreferencesDebugPane.swift +10 -10
  152. package/Sources/Runic/Views/Preferences/PreferencesGeneralPane.swift +40 -21
  153. package/Sources/Runic/Views/Preferences/PreferencesHelpPane.swift +7 -7
  154. package/Sources/Runic/Views/Preferences/PreferencesIntegrationsPane.swift +108 -33
  155. package/Sources/Runic/Views/Preferences/PreferencesPerformancePane.swift +26 -23
  156. package/Sources/Runic/Views/Preferences/PreferencesProvidersPane.swift +271 -226
  157. package/Sources/Runic/Views/Preferences/PreferencesSelection.swift +6 -2
  158. package/Sources/Runic/Views/Preferences/PreferencesSyncPane.swift +7 -5
  159. package/Sources/Runic/Views/Preferences/PreferencesView.swift +38 -31
  160. package/Sources/Runic/Views/Rating/QualityRatingView.swift +11 -11
  161. package/Sources/Runic/Views/Team/TeamDashboardView.swift +29 -24
  162. package/Sources/Runic/Views/Team/TeamInviteSheet.swift +16 -16
  163. package/Sources/Runic/Views/Team/TeamManagementView.swift +50 -49
  164. package/Sources/Runic/Views/Team/TeamMemberRow.swift +8 -8
  165. package/Sources/RunicCLI/CLIEntry.swift +83 -42
  166. package/Sources/RunicCLI/CLIRenderer.swift +1 -1
  167. package/Sources/RunicCLI/Commands/EnhancedUsageCommand.swift +60 -60
  168. package/Sources/RunicCLI/Commands/ModelsCommand.swift +45 -44
  169. package/Sources/RunicCLI/Commands/ProjectsCommand.swift +83 -69
  170. package/Sources/RunicCLI/Commands/ResetCommand.swift +50 -49
  171. package/Sources/RunicCLI/Commands/UsageLedgerSourceFactory.swift +31 -32
  172. package/Sources/RunicClaudeWebProbe/main.swift +1 -1
  173. package/Sources/RunicCore/AlertRuleStore.swift +20 -20
  174. package/Sources/RunicCore/BrowserCookieImportOrder.swift +3 -3
  175. package/Sources/RunicCore/CostUsageModels.swift +1 -1
  176. package/Sources/RunicCore/CustomProviders/CustomProviderModels.swift +29 -30
  177. package/Sources/RunicCore/CustomProviders/GenericProviderFetcher.swift +80 -71
  178. package/Sources/RunicCore/CustomProviders/ProviderTemplates.swift +53 -109
  179. package/Sources/RunicCore/Host/PTY/TTYCommandRunner.swift +3 -3
  180. package/Sources/RunicCore/Integrations/GitHubIntegration.swift +3 -3
  181. package/Sources/RunicCore/Logging/OSLogLogHandler.swift +6 -6
  182. package/Sources/RunicCore/Models/EnhancedUsageModels.swift +47 -48
  183. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardBrowserCookieImporter.swift +1 -1
  184. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardFetcher.swift +1 -1
  185. package/Sources/RunicCore/Performance/PerformanceModels.swift +4 -4
  186. package/Sources/RunicCore/Performance/PerformanceStorageImpl.swift +81 -64
  187. package/Sources/RunicCore/Policy/UsagePolicyEngine.swift +2 -2
  188. package/Sources/RunicCore/ProjectBudgetStore.swift +15 -12
  189. package/Sources/RunicCore/Providers/Antigravity/AntigravityProviderDescriptor.swift +4 -2
  190. package/Sources/RunicCore/Providers/Antigravity/AntigravityStatusProbe.swift +2 -2
  191. package/Sources/RunicCore/Providers/Auggie/AuggieProviderDescriptor.swift +2 -2
  192. package/Sources/RunicCore/Providers/Auggie/AuggieUsageFetcher.swift +3 -3
  193. package/Sources/RunicCore/Providers/Azure/AzureProviderDescriptor.swift +8 -8
  194. package/Sources/RunicCore/Providers/Azure/AzureUsageFetcher.swift +5 -3
  195. package/Sources/RunicCore/Providers/Bedrock/BedrockProviderDescriptor.swift +6 -6
  196. package/Sources/RunicCore/Providers/Bedrock/BedrockUsageFetcher.swift +3 -7
  197. package/Sources/RunicCore/Providers/Cerebras/CerebrasProviderDescriptor.swift +2 -2
  198. package/Sources/RunicCore/Providers/Cerebras/CerebrasUsageFetcher.swift +2 -2
  199. package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthUsageFetcher.swift +3 -3
  200. package/Sources/RunicCore/Providers/Claude/ClaudeProviderDescriptor.swift +4 -2
  201. package/Sources/RunicCore/Providers/Claude/ClaudeStatusProbe.swift +4 -4
  202. package/Sources/RunicCore/Providers/Claude/ClaudeUsageDataSource.swift +3 -1
  203. package/Sources/RunicCore/Providers/Claude/ClaudeWeb/ClaudeWebAPIFetcher.swift +1 -1
  204. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthCredentials.swift +1 -0
  205. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthUsageFetcher.swift +12 -1
  206. package/Sources/RunicCore/Providers/Codex/CodexProviderDescriptor.swift +4 -2
  207. package/Sources/RunicCore/Providers/Codex/CodexUsageDataSource.swift +3 -1
  208. package/Sources/RunicCore/Providers/Codex/CodexWebDashboardStrategy.swift +5 -3
  209. package/Sources/RunicCore/Providers/Cohere/CohereProviderDescriptor.swift +2 -2
  210. package/Sources/RunicCore/Providers/Cohere/CohereUsageFetcher.swift +3 -3
  211. package/Sources/RunicCore/Providers/Copilot/CopilotGitHubCLITokenReader.swift +7 -4
  212. package/Sources/RunicCore/Providers/Copilot/CopilotProviderDescriptor.swift +4 -4
  213. package/Sources/RunicCore/Providers/Copilot/CopilotUsageFetcher.swift +5 -3
  214. package/Sources/RunicCore/Providers/Copilot/CopilotVSCodeTokenReader.swift +9 -10
  215. package/Sources/RunicCore/Providers/Cursor/CursorProviderDescriptor.swift +4 -2
  216. package/Sources/RunicCore/Providers/Cursor/CursorStatusProbe.swift +1 -0
  217. package/Sources/RunicCore/Providers/DeepSeek/DeepSeekProviderDescriptor.swift +2 -2
  218. package/Sources/RunicCore/Providers/DeepSeek/DeepSeekUsageFetcher.swift +2 -2
  219. package/Sources/RunicCore/Providers/Factory/FactoryLocalStorageImporter.swift +4 -4
  220. package/Sources/RunicCore/Providers/Factory/FactoryProviderDescriptor.swift +4 -2
  221. package/Sources/RunicCore/Providers/Factory/FactoryStatusProbe.swift +3 -2
  222. package/Sources/RunicCore/Providers/Fireworks/FireworksProviderDescriptor.swift +2 -2
  223. package/Sources/RunicCore/Providers/Fireworks/FireworksUsageFetcher.swift +2 -2
  224. package/Sources/RunicCore/Providers/Gemini/GeminiProviderDescriptor.swift +4 -2
  225. package/Sources/RunicCore/Providers/Gemini/GeminiStatusProbe.swift +6 -2
  226. package/Sources/RunicCore/Providers/Groq/GroqProviderDescriptor.swift +2 -2
  227. package/Sources/RunicCore/Providers/Groq/GroqUsageFetcher.swift +2 -2
  228. package/Sources/RunicCore/Providers/Kimi/KimiProviderDescriptor.swift +2 -2
  229. package/Sources/RunicCore/Providers/Kimi/KimiUsageFetcher.swift +2 -2
  230. package/Sources/RunicCore/Providers/MiniMax/MiniMaxProviderDescriptor.swift +10 -5
  231. package/Sources/RunicCore/Providers/MiniMax/MiniMaxUsageFetcher.swift +8 -11
  232. package/Sources/RunicCore/Providers/MiniMax/MiniMaxWebUsageFetcher.swift +10 -10
  233. package/Sources/RunicCore/Providers/Mistral/MistralProviderDescriptor.swift +2 -2
  234. package/Sources/RunicCore/Providers/Mistral/MistralUsageFetcher.swift +2 -2
  235. package/Sources/RunicCore/Providers/OpenRouter/OpenRouterProviderDescriptor.swift +2 -2
  236. package/Sources/RunicCore/Providers/OpenRouter/OpenRouterUsageFetcher.swift +25 -16
  237. package/Sources/RunicCore/Providers/Perplexity/PerplexityProviderDescriptor.swift +2 -2
  238. package/Sources/RunicCore/Providers/Perplexity/PerplexityUsageFetcher.swift +2 -2
  239. package/Sources/RunicCore/Providers/ProviderFetchPlan.swift +2 -2
  240. package/Sources/RunicCore/Providers/ProviderTokenResolver.swift +2 -2
  241. package/Sources/RunicCore/Providers/Qwen/QwenProviderDescriptor.swift +5 -3
  242. package/Sources/RunicCore/Providers/Qwen/QwenUsageStats.swift +27 -16
  243. package/Sources/RunicCore/Providers/SambaNova/SambaNovaProviderDescriptor.swift +2 -2
  244. package/Sources/RunicCore/Providers/SambaNova/SambaNovaUsageFetcher.swift +2 -2
  245. package/Sources/RunicCore/Providers/Together/TogetherProviderDescriptor.swift +2 -2
  246. package/Sources/RunicCore/Providers/Together/TogetherUsageFetcher.swift +2 -2
  247. package/Sources/RunicCore/Providers/VertexAI/VertexAIProviderDescriptor.swift +5 -5
  248. package/Sources/RunicCore/Providers/VertexAI/VertexAISettingsReader.swift +1 -1
  249. package/Sources/RunicCore/Providers/VertexAI/VertexAIUsageFetcher.swift +3 -3
  250. package/Sources/RunicCore/Providers/XAI/XAIProviderDescriptor.swift +2 -2
  251. package/Sources/RunicCore/Providers/XAI/XAIUsageFetcher.swift +2 -2
  252. package/Sources/RunicCore/Providers/Zai/ZaiProviderDescriptor.swift +4 -2
  253. package/Sources/RunicCore/Providers/Zai/ZaiUsageStats.swift +51 -30
  254. package/Sources/RunicCore/Sync/BackgroundSyncManager.swift +76 -77
  255. package/Sources/RunicCore/Sync/SyncConflictResolver.swift +55 -58
  256. package/Sources/RunicCore/Sync/SyncProtocol.swift +21 -22
  257. package/Sources/RunicCore/Sync/SyncRecord.swift +46 -49
  258. package/Sources/RunicCore/Sync/SyncUsageExample.swift +44 -50
  259. package/Sources/RunicCore/Sync/TeamSyncRecords.swift +94 -101
  260. package/Sources/RunicCore/Sync/iCloudSyncEngine.swift +51 -46
  261. package/Sources/RunicCore/Team/TeamModels.swift +111 -110
  262. package/Sources/RunicCore/Team/TeamStore.swift +126 -109
  263. package/Sources/RunicCore/UsageFetcher.swift +2 -2
  264. package/Sources/RunicCore/UsageFormatter.swift +25 -25
  265. package/Sources/RunicCore/UsageLedger/ClaudeUsageLogSource.swift +141 -29
  266. package/Sources/RunicCore/UsageLedger/CodexUsageLogSource.swift +59 -5
  267. package/Sources/RunicCore/UsageLedger/LedgerCache.swift +161 -0
  268. package/Sources/RunicCore/UsageLedger/OTelGenAILedgerAdapter.swift +1 -1
  269. package/Sources/RunicCore/UsageLedger/UsageLedgerAggregator.swift +40 -25
  270. package/Sources/RunicCore/UsageLedger/UsageLedgerInsightsAdvisor.swift +1 -1
  271. package/Sources/RunicCore/UsageLedger/UsageLedgerProjectIdentity.swift +55 -16
  272. package/Sources/RunicCore/Vendored/CostUsage/CostUsageCache.swift +6 -6
  273. package/Sources/RunicCore/Vendored/CostUsage/CostUsageJsonl.swift +1 -1
  274. package/Sources/RunicCore/Vendored/CostUsage/CostUsagePricing.swift +2 -2
  275. package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner.swift +5 -5
  276. package/Tests/RunicTests/AppDelegateTests.swift +8 -3
  277. package/Tests/RunicTests/BrowserCookieOrderLabelTests.swift +2 -3
  278. package/Tests/RunicTests/CLIArgumentParsingTests.swift +3 -4
  279. package/Tests/RunicTests/CLICostTests.swift +6 -7
  280. package/Tests/RunicTests/CLIProviderSelectionTests.swift +2 -3
  281. package/Tests/RunicTests/CLISnapshotTests.swift +3 -4
  282. package/Tests/RunicTests/CLIWebFallbackTests.swift +3 -4
  283. package/Tests/RunicTests/ClaudeOAuthTests.swift +11 -12
  284. package/Tests/RunicTests/ClaudeResilienceTests.swift +3 -4
  285. package/Tests/RunicTests/ClaudeUsageTests.swift +20 -21
  286. package/Tests/RunicTests/CodexOAuthTests.swift +7 -8
  287. package/Tests/RunicTests/CodexUsageLogSourceTests.swift +1 -3
  288. package/Tests/RunicTests/CopilotTokenResolverTests.swift +5 -6
  289. package/Tests/RunicTests/CopilotVSCodeTokenReaderTests.swift +4 -5
  290. package/Tests/RunicTests/CostUsageDecodingTests.swift +15 -17
  291. package/Tests/RunicTests/CostUsagePricingTests.swift +5 -7
  292. package/Tests/RunicTests/CostUsageScannerTests.swift +10 -12
  293. package/Tests/RunicTests/CursorStatusProbeTests.swift +15 -16
  294. package/Tests/RunicTests/FactoryStatusProbeTests.swift +3 -5
  295. package/Tests/RunicTests/GeminiLoginAlertTests.swift +3 -4
  296. package/Tests/RunicTests/GeminiStatusProbeAPITests.swift +11 -11
  297. package/Tests/RunicTests/GeminiStatusProbePlanTests.swift +8 -8
  298. package/Tests/RunicTests/GeminiStatusProbeTests.swift +20 -21
  299. package/Tests/RunicTests/GoogleWorkspaceStatusTests.swift +2 -3
  300. package/Tests/RunicTests/InstallOriginTests.swift +1 -2
  301. package/Tests/RunicTests/KeyboardShortcutsBundleTests.swift +2 -2
  302. package/Tests/RunicTests/LiveAccountTests.swift +3 -3
  303. package/Tests/RunicTests/LoadingPatternTests.swift +3 -4
  304. package/Tests/RunicTests/MenuCardModelTests.swift +33 -34
  305. package/Tests/RunicTests/MiniMaxCookieHeaderStoreTestSupport.swift +4 -1
  306. package/Tests/RunicTests/MiniMaxGroupIDStoreTestSupport.swift +4 -1
  307. package/Tests/RunicTests/MiniMaxParsingTests.swift +4 -5
  308. package/Tests/RunicTests/MiniMaxTokenStoreTestSupport.swift +4 -1
  309. package/Tests/RunicTests/OTelGenAILedgerAdapterTests.swift +4 -6
  310. package/Tests/RunicTests/OpenAIDashboardBrowserCookieImporterTests.swift +1 -2
  311. package/Tests/RunicTests/OpenAIDashboardFetcherCreditsWaitTests.swift +5 -6
  312. package/Tests/RunicTests/OpenAIDashboardOffscreenHostTests.swift +2 -3
  313. package/Tests/RunicTests/OpenAIDashboardParserTests.swift +12 -13
  314. package/Tests/RunicTests/OpenAIWebAccountSwitchTests.swift +17 -6
  315. package/Tests/RunicTests/OpenRouterTokenStoreTestSupport.swift +52 -13
  316. package/Tests/RunicTests/PathBuilderTests.swift +14 -15
  317. package/Tests/RunicTests/ProviderFetchPipelineTests.swift +3 -4
  318. package/Tests/RunicTests/ProviderIconResourcesTests.swift +1 -2
  319. package/Tests/RunicTests/ProviderMetadataStatusLinkTests.swift +1 -2
  320. package/Tests/RunicTests/ProviderSettingsDescriptorTests.swift +53 -19
  321. package/Tests/RunicTests/ProviderToggleStoreTests.swift +10 -11
  322. package/Tests/RunicTests/RunicTests.swift +6 -7
  323. package/Tests/RunicTests/SessionQuotaNotificationLogicTests.swift +5 -6
  324. package/Tests/RunicTests/SettingsStoreTests.swift +149 -45
  325. package/Tests/RunicTests/StatusItemAnimationTests.swift +8 -3
  326. package/Tests/RunicTests/StatusMenuTests.swift +63 -22
  327. package/Tests/RunicTests/StatusProbeTests.swift +28 -29
  328. package/Tests/RunicTests/SubprocessRunnerTests.swift +1 -3
  329. package/Tests/RunicTests/SubscriptionDetectionTests.swift +8 -9
  330. package/Tests/RunicTests/TTYCommandRunnerTests.swift +8 -9
  331. package/Tests/RunicTests/TeamShowbackExporterTests.swift +2 -4
  332. package/Tests/RunicTests/TextParsingTests.swift +1 -2
  333. package/Tests/RunicTests/UsageFormatterTests.swift +15 -16
  334. package/Tests/RunicTests/UsageLedgerAnomalyDetectionTests.swift +12 -14
  335. package/Tests/RunicTests/UsageLedgerForecastTests.swift +4 -6
  336. package/Tests/RunicTests/UsageLedgerInsightsAdvisorTests.swift +7 -9
  337. package/Tests/RunicTests/UsageLedgerProjectNameTests.swift +6 -8
  338. package/Tests/RunicTests/UsagePaceTests.swift +5 -6
  339. package/Tests/RunicTests/UsagePaceTextTests.swift +8 -9
  340. package/Tests/RunicTests/UsagePolicyEngineTests.swift +3 -5
  341. package/Tests/RunicTests/WidgetSnapshotTests.swift +1 -3
  342. package/Tests/RunicTests/ZaiProviderTests.swift +3 -5
  343. package/Tests/RunicTests/ZaiTokenStoreTestSupport.swift +4 -1
  344. package/appcast.xml +36 -37
  345. package/package.json +1 -1
  346. package/runic.png +0 -0
  347. package/runic.svg +15 -0
  348. package/version.env +2 -2
@@ -1,27 +1,26 @@
1
- /// EnhancedUsageCommand.swift
2
- /// Runic CLI - Enhanced Usage Display
3
- ///
4
- /// Enhanced version of the usage command with additional features:
5
- /// - Multiple display modes (summary, detailed, breakdown)
6
- /// - Historical trending
7
- /// - Cost projections
8
- /// - Comparative analysis across providers
9
- ///
10
- /// Usage:
11
- /// runic usage-enhanced [options]
12
- ///
13
- /// Examples:
14
- /// runic usage-enhanced --mode summary # Quick overview
15
- /// runic usage-enhanced --mode detailed # Detailed breakdown
16
- /// runic usage-enhanced --mode trending # Usage trends
1
+ // EnhancedUsageCommand.swift
2
+ // Runic CLI - Enhanced Usage Display
3
+ //
4
+ // Enhanced version of the usage command with additional features:
5
+ // - Multiple display modes (summary, detailed, breakdown)
6
+ // - Historical trending
7
+ // - Cost projections
8
+ // - Comparative analysis across providers
9
+ //
10
+ // Usage:
11
+ // runic usage-enhanced [options]
12
+ //
13
+ // Examples:
14
+ // runic usage-enhanced --mode summary # Quick overview
15
+ // runic usage-enhanced --mode detailed # Detailed breakdown
16
+ // runic usage-enhanced --mode trending # Usage trends
17
17
 
18
- import RunicCore
19
- import Helix
20
18
  import Foundation
19
+ import Helix
20
+ import RunicCore
21
21
 
22
22
  /// Enhanced usage command with additional analytics
23
23
  public enum EnhancedUsageCommand {
24
-
25
24
  /// Command signature defining available options and flags
26
25
  public static var signature: CommandSignature {
27
26
  CommandSignature(
@@ -106,7 +105,7 @@ public enum EnhancedUsageCommand {
106
105
 
107
106
  /// Execute the enhanced usage command
108
107
  public static func run(_ invocation: CommandInvocation) async {
109
- let config = parseConfiguration(invocation)
108
+ let config = self.parseConfiguration(invocation)
110
109
 
111
110
  do {
112
111
  let data = try await loadUsageData(
@@ -115,12 +114,12 @@ public enum EnhancedUsageCommand {
115
114
  includeCost: config.showCost)
116
115
 
117
116
  if config.isJSON {
118
- outputJSON(data, config: config)
117
+ self.outputJSON(data, config: config)
119
118
  } else {
120
- outputText(data, config: config)
119
+ self.outputText(data, config: config)
121
120
  }
122
121
  } catch {
123
- exitWithError("Failed to load usage data: \(error.localizedDescription)")
122
+ self.exitWithError("Failed to load usage data: \(error.localizedDescription)")
124
123
  }
125
124
  }
126
125
 
@@ -161,7 +160,7 @@ public enum EnhancedUsageCommand {
161
160
 
162
161
  let mode = Configuration.DisplayMode(rawValue: modeArg.lowercased()) ?? .summary
163
162
  let days = daysArg.flatMap(Int.init) ?? 7
164
- let providers = resolveProviders(providerArg)
163
+ let providers = self.resolveProviders(providerArg)
165
164
 
166
165
  return Configuration(
167
166
  providers: providers,
@@ -185,7 +184,7 @@ public enum EnhancedUsageCommand {
185
184
  }
186
185
 
187
186
  guard let provider = UsageProvider(rawValue: arg) else {
188
- exitWithError("Unknown provider: \(arg)")
187
+ self.exitWithError("Unknown provider: \(arg)")
189
188
  }
190
189
 
191
190
  return [provider]
@@ -269,8 +268,8 @@ public enum EnhancedUsageCommand {
269
268
  private static func loadUsageData(
270
269
  providers: [UsageProvider],
271
270
  days: Int,
272
- includeCost: Bool
273
- ) async throws -> EnhancedUsageData {
271
+ includeCost: Bool) async throws -> EnhancedUsageData
272
+ {
274
273
  let fetcher = UsageFetcher()
275
274
  let _ = includeCost ? CostUsageFetcher() : nil
276
275
  var providerData: [ProviderUsageData] = []
@@ -291,12 +290,12 @@ public enum EnhancedUsageCommand {
291
290
 
292
291
  let outcome = await descriptor.fetchOutcome(context: context)
293
292
 
294
- if case .success(let result) = outcome.result {
293
+ if case let .success(result) = outcome.result {
295
294
  let trending = try? await loadTrendingData(
296
295
  provider: provider,
297
296
  days: days)
298
297
 
299
- let data = buildProviderData(
298
+ let data = self.buildProviderData(
300
299
  provider: provider,
301
300
  snapshot: result.usage,
302
301
  credits: result.credits,
@@ -307,8 +306,8 @@ public enum EnhancedUsageCommand {
307
306
  }
308
307
  }
309
308
 
310
- let summary = buildSummary(providerData: providerData)
311
- let comparison = buildComparison(providerData: providerData)
309
+ let summary = self.buildSummary(providerData: providerData)
310
+ let comparison = self.buildComparison(providerData: providerData)
312
311
 
313
312
  return EnhancedUsageData(
314
313
  providers: providerData,
@@ -321,8 +320,8 @@ public enum EnhancedUsageCommand {
321
320
  snapshot: UsageSnapshot,
322
321
  credits: CreditsSnapshot?,
323
322
  metadata: ProviderMetadata,
324
- trending: [DailyTrend]?
325
- ) -> ProviderUsageData {
323
+ trending: [DailyTrend]?) -> ProviderUsageData
324
+ {
326
325
  var windows: [WindowData] = []
327
326
 
328
327
  windows.append(WindowData(
@@ -356,8 +355,8 @@ public enum EnhancedUsageCommand {
356
355
 
357
356
  private static func loadTrendingData(
358
357
  provider: UsageProvider,
359
- days: Int
360
- ) async throws -> [DailyTrend]? {
358
+ days: Int) async throws -> [DailyTrend]?
359
+ {
361
360
  let source = UsageLedgerSourceFactory.source(for: provider, now: Date(), maxAgeDays: days)
362
361
 
363
362
  guard let source else { return nil }
@@ -377,8 +376,8 @@ public enum EnhancedUsageCommand {
377
376
  }
378
377
 
379
378
  private static func buildSummary(
380
- providerData: [ProviderUsageData]
381
- ) -> UsageSummary? {
379
+ providerData: [ProviderUsageData]) -> UsageSummary?
380
+ {
382
381
  guard !providerData.isEmpty else { return nil }
383
382
 
384
383
  let totalTokens = providerData.reduce(0) { sum, data in
@@ -405,8 +404,8 @@ public enum EnhancedUsageCommand {
405
404
  }
406
405
 
407
406
  private static func buildComparison(
408
- providerData: [ProviderUsageData]
409
- ) -> ProviderComparison? {
407
+ providerData: [ProviderUsageData]) -> ProviderComparison?
408
+ {
410
409
  guard providerData.count > 1 else { return nil }
411
410
 
412
411
  let comparisons = providerData.map { data in
@@ -439,7 +438,8 @@ public enum EnhancedUsageCommand {
439
438
  }
440
439
 
441
440
  guard let jsonData = try? encoder.encode(data),
442
- let text = String(data: jsonData, encoding: .utf8) else {
441
+ let text = String(data: jsonData, encoding: .utf8)
442
+ else {
443
443
  print("{}")
444
444
  return
445
445
  }
@@ -450,23 +450,23 @@ public enum EnhancedUsageCommand {
450
450
  private static func outputText(_ data: EnhancedUsageData, config: Configuration) {
451
451
  switch config.mode {
452
452
  case .summary:
453
- outputSummaryMode(data, config: config)
453
+ self.outputSummaryMode(data, config: config)
454
454
  case .detailed:
455
- outputDetailedMode(data, config: config)
455
+ self.outputDetailedMode(data, config: config)
456
456
  case .breakdown:
457
- outputBreakdownMode(data, config: config)
457
+ self.outputBreakdownMode(data, config: config)
458
458
  case .trending:
459
- outputTrendingMode(data, config: config)
459
+ self.outputTrendingMode(data, config: config)
460
460
  }
461
461
  }
462
462
 
463
463
  private static func outputSummaryMode(_ data: EnhancedUsageData, config: Configuration) {
464
- printHeader("Usage Summary", useColor: config.useColor)
464
+ self.printHeader("Usage Summary", useColor: config.useColor)
465
465
  print("")
466
466
 
467
467
  if let summary = data.summary {
468
468
  print("Providers: \(summary.totalProviders)")
469
- print("Total Tokens: \(formatNumber(summary.totalTokens))")
469
+ print("Total Tokens: \(self.formatNumber(summary.totalTokens))")
470
470
  print("Average Usage: \(String(format: "%.1f", summary.averageUsagePercent))%")
471
471
  print("Highest Usage: \(summary.highestUsageProvider)")
472
472
  print("")
@@ -475,7 +475,7 @@ public enum EnhancedUsageCommand {
475
475
  for providerData in data.providers {
476
476
  print(providerData.providerName)
477
477
  for window in providerData.windows {
478
- let bar = progressBar(
478
+ let bar = self.progressBar(
479
479
  used: window.usedPercent,
480
480
  width: 20,
481
481
  useColor: config.useColor)
@@ -487,14 +487,14 @@ public enum EnhancedUsageCommand {
487
487
  }
488
488
 
489
489
  private static func outputDetailedMode(_ data: EnhancedUsageData, config: Configuration) {
490
- printHeader("Detailed Usage Information", useColor: config.useColor)
490
+ self.printHeader("Detailed Usage Information", useColor: config.useColor)
491
491
  print("")
492
492
 
493
493
  for (index, providerData) in data.providers.enumerated() {
494
494
  if index > 0 { print("") }
495
495
 
496
496
  if config.useColor {
497
- print(ansi("1;36", providerData.providerName))
497
+ print(self.ansi("1;36", providerData.providerName))
498
498
  } else {
499
499
  print(providerData.providerName)
500
500
  }
@@ -503,7 +503,7 @@ public enum EnhancedUsageCommand {
503
503
  print("")
504
504
  print(" \(window.name):")
505
505
  if let used = window.used, let limit = window.limit {
506
- print(" Used: \(formatNumber(used)) / \(formatNumber(limit))")
506
+ print(" Used: \(self.formatNumber(used)) / \(self.formatNumber(limit))")
507
507
  }
508
508
  print(" Percent: \(String(format: "%.1f", window.usedPercent))%")
509
509
  if let reset = window.resetDescription {
@@ -514,14 +514,14 @@ public enum EnhancedUsageCommand {
514
514
  }
515
515
 
516
516
  private static func outputBreakdownMode(_ data: EnhancedUsageData, config: Configuration) {
517
- printHeader("Token Breakdown", useColor: config.useColor)
517
+ self.printHeader("Token Breakdown", useColor: config.useColor)
518
518
  print("")
519
519
  print("Note: Detailed token breakdown requires historical log data.")
520
520
  print("Use 'runic insights --view models' for model-level breakdown.")
521
521
  }
522
522
 
523
523
  private static func outputTrendingMode(_ data: EnhancedUsageData, config: Configuration) {
524
- printHeader("Usage Trends", useColor: config.useColor)
524
+ self.printHeader("Usage Trends", useColor: config.useColor)
525
525
  print("")
526
526
 
527
527
  for providerData in data.providers {
@@ -529,7 +529,7 @@ public enum EnhancedUsageCommand {
529
529
 
530
530
  if let trends = providerData.trending, !trends.isEmpty {
531
531
  for trend in trends.suffix(10) {
532
- let tokens = formatNumber(trend.totalTokens)
532
+ let tokens = self.formatNumber(trend.totalTokens)
533
533
  let cost = trend.cost.map { String(format: "$%.4f", $0) } ?? "n/a"
534
534
  print(" \(trend.date): \(tokens) tokens (\(cost))")
535
535
  }
@@ -548,26 +548,26 @@ public enum EnhancedUsageCommand {
548
548
  guard useColor else { return "[\(bar)]" }
549
549
 
550
550
  let color = switch used {
551
- case 90...: "31" // red
552
- case 75...: "33" // yellow
553
- default: "32" // green
551
+ case 90...: "31" // red
552
+ case 75...: "33" // yellow
553
+ default: "32" // green
554
554
  }
555
555
 
556
- return "[\(ansi(color, bar))]"
556
+ return "[\(self.ansi(color, bar))]"
557
557
  }
558
558
 
559
559
  private static func formatNumber(_ n: Int) -> String {
560
560
  if n >= 1_000_000 {
561
561
  return String(format: "%.1fM", Double(n) / 1_000_000)
562
- } else if n >= 1_000 {
563
- return String(format: "%.1fK", Double(n) / 1_000)
562
+ } else if n >= 1000 {
563
+ return String(format: "%.1fK", Double(n) / 1000)
564
564
  }
565
565
  return "\(n)"
566
566
  }
567
567
 
568
568
  private static func printHeader(_ text: String, useColor: Bool) {
569
569
  if useColor {
570
- print(ansi("1;36", text))
570
+ print(self.ansi("1;36", text))
571
571
  } else {
572
572
  print(text)
573
573
  }
@@ -1,21 +1,21 @@
1
- /// ModelsCommand.swift
2
- /// Runic CLI - Model Usage Breakdown
3
- ///
4
- /// Displays which AI models were used across different providers,
5
- /// showing token consumption and cost breakdown by model type.
6
- ///
7
- /// Usage:
8
- /// runic models [--provider <name>] [--days <n>] [--json] [--pretty] [--no-color]
9
- ///
10
- /// Examples:
11
- /// runic models # Show all models used
12
- /// runic models --provider claude # Claude models only
13
- /// runic models --days 7 # Last 7 days
14
- /// runic models --json --pretty # JSON output
1
+ // ModelsCommand.swift
2
+ // Runic CLI - Model Usage Breakdown
3
+ //
4
+ // Displays which AI models were used across different providers,
5
+ // showing token consumption and cost breakdown by model type.
6
+ //
7
+ // Usage:
8
+ // runic models [--provider <name>] [--days <n>] [--json] [--pretty] [--no-color]
9
+ //
10
+ // Examples:
11
+ // runic models # Show all models used
12
+ // runic models --provider claude # Claude models only
13
+ // runic models --days 7 # Last 7 days
14
+ // runic models --json --pretty # JSON output
15
15
 
16
- import RunicCore
17
- import Helix
18
16
  import Foundation
17
+ import Helix
18
+ import RunicCore
19
19
 
20
20
  /// Main entry point for the models command
21
21
  public enum ModelsCommand {
@@ -112,7 +112,7 @@ public enum ModelsCommand {
112
112
 
113
113
  /// Execute the models command
114
114
  public static func run(_ invocation: CommandInvocation) async {
115
- let config = parseConfiguration(invocation)
115
+ let config = self.parseConfiguration(invocation)
116
116
 
117
117
  do {
118
118
  let entries = try await loadUsageEntries(
@@ -120,7 +120,7 @@ public enum ModelsCommand {
120
120
  maxAgeDays: config.days)
121
121
 
122
122
  guard !entries.isEmpty else {
123
- exitWithError("No model usage data found for the specified criteria.")
123
+ self.exitWithError("No model usage data found for the specified criteria.")
124
124
  }
125
125
 
126
126
  let summaries = UsageLedgerAggregator.modelSummaries(
@@ -128,12 +128,12 @@ public enum ModelsCommand {
128
128
  groupByProject: config.groupByProject)
129
129
 
130
130
  if config.isJSON {
131
- outputJSON(summaries, pretty: config.isPretty)
131
+ self.outputJSON(summaries, pretty: config.isPretty)
132
132
  } else {
133
- outputText(summaries, useColor: config.useColor)
133
+ self.outputText(summaries, useColor: config.useColor)
134
134
  }
135
135
  } catch {
136
- exitWithError("Failed to load usage data: \(error.localizedDescription)")
136
+ self.exitWithError("Failed to load usage data: \(error.localizedDescription)")
137
137
  }
138
138
  }
139
139
 
@@ -160,7 +160,7 @@ public enum ModelsCommand {
160
160
  let groupByProject = invocation.parsedValues.flags.contains("groupByProject")
161
161
 
162
162
  let days = daysArg.flatMap(Int.init) ?? 30
163
- let providers = resolveProviders(providerArg)
163
+ let providers = self.resolveProviders(providerArg)
164
164
 
165
165
  return Configuration(
166
166
  providers: providers,
@@ -181,7 +181,7 @@ public enum ModelsCommand {
181
181
  }
182
182
 
183
183
  guard let provider = UsageProvider(rawValue: arg) else {
184
- exitWithError("Unknown provider: \(arg)")
184
+ self.exitWithError("Unknown provider: \(arg)")
185
185
  }
186
186
 
187
187
  return [provider]
@@ -191,8 +191,8 @@ public enum ModelsCommand {
191
191
 
192
192
  private static func loadUsageEntries(
193
193
  providers: [UsageProvider],
194
- maxAgeDays: Int
195
- ) async throws -> [UsageLedgerEntry] {
194
+ maxAgeDays: Int) async throws -> [UsageLedgerEntry]
195
+ {
196
196
  let now = Date()
197
197
  var allEntries: [UsageLedgerEntry] = []
198
198
 
@@ -221,7 +221,8 @@ public enum ModelsCommand {
221
221
  let enriched = summaries.map(EnrichedModelSummary.init)
222
222
 
223
223
  guard let data = try? encoder.encode(enriched),
224
- let text = String(data: data, encoding: .utf8) else {
224
+ let text = String(data: data, encoding: .utf8)
225
+ else {
225
226
  print("[]")
226
227
  return
227
228
  }
@@ -235,11 +236,11 @@ public enum ModelsCommand {
235
236
  return
236
237
  }
237
238
 
238
- printHeader("Model Usage Breakdown", useColor: useColor)
239
+ self.printHeader("Model Usage Breakdown", useColor: useColor)
239
240
  print("")
240
241
 
241
242
  // Calculate column widths
242
- let maxModelWidth = summaries.map { $0.model.count }.max() ?? 20
243
+ let maxModelWidth = summaries.map(\.model.count).max() ?? 20
243
244
  let modelWidth = min(max(maxModelWidth, 15), 40)
244
245
  let contextWidth = 11
245
246
 
@@ -253,7 +254,7 @@ public enum ModelsCommand {
253
254
  "COST",
254
255
  "CONTEXT")
255
256
  if useColor {
256
- print(ansi("1;37", header))
257
+ print(self.ansi("1;37", header))
257
258
  print(String(repeating: "-", count: modelWidth + 58))
258
259
  } else {
259
260
  print(header)
@@ -265,11 +266,11 @@ public enum ModelsCommand {
265
266
  var totalCost = 0.0
266
267
 
267
268
  for summary in summaries {
268
- let model = truncate(summary.model, maxWidth: modelWidth)
269
+ let model = self.truncate(summary.model, maxWidth: modelWidth)
269
270
  let provider = summary.provider.rawValue
270
- let tokens = formatNumber(summary.totals.totalTokens)
271
+ let tokens = self.formatNumber(summary.totals.totalTokens)
271
272
  let requests = "\(summary.entryCount)"
272
- let cost = formatCost(summary.totals.costUSD)
273
+ let cost = self.formatCost(summary.totals.costUSD)
273
274
  let context = UsageFormatter.modelContextLabel(for: summary.model) ?? "n/a"
274
275
 
275
276
  let line = String(
@@ -277,7 +278,7 @@ public enum ModelsCommand {
277
278
  model, provider, tokens, requests, cost, context)
278
279
 
279
280
  if useColor {
280
- print(colorizeByUsage(line, tokens: summary.totals.totalTokens))
281
+ print(self.colorizeByUsage(line, tokens: summary.totals.totalTokens))
281
282
  } else {
282
283
  print(line)
283
284
  }
@@ -294,10 +295,10 @@ public enum ModelsCommand {
294
295
  let totalLine = String(
295
296
  format: "%-\(modelWidth)s %-12s %15s %12s %10s %-\(contextWidth)s",
296
297
  "TOTAL", "", formatNumber(totalTokens), "\(totalRequests)",
297
- formatCost(totalCost > 0 ? totalCost : nil), " ")
298
+ formatCost(totalCost > 0 ? totalCost : nil), " ")
298
299
 
299
300
  if useColor {
300
- print(ansi("1;36", totalLine))
301
+ print(self.ansi("1;36", totalLine))
301
302
  } else {
302
303
  print(totalLine)
303
304
  }
@@ -308,14 +309,14 @@ public enum ModelsCommand {
308
309
  private static func formatNumber(_ n: Int) -> String {
309
310
  if n >= 1_000_000 {
310
311
  return String(format: "%.1fM", Double(n) / 1_000_000)
311
- } else if n >= 1_000 {
312
- return String(format: "%.1fK", Double(n) / 1_000)
312
+ } else if n >= 1000 {
313
+ return String(format: "%.1fK", Double(n) / 1000)
313
314
  }
314
315
  return "\(n)"
315
316
  }
316
317
 
317
318
  private static func formatCost(_ cost: Double?) -> String {
318
- guard let cost = cost, cost > 0 else {
319
+ guard let cost, cost > 0 else {
319
320
  return "n/a"
320
321
  }
321
322
  return String(format: "$%.4f", cost)
@@ -331,7 +332,7 @@ public enum ModelsCommand {
331
332
 
332
333
  private static func printHeader(_ text: String, useColor: Bool) {
333
334
  if useColor {
334
- print(ansi("1;36", text))
335
+ print(self.ansi("1;36", text))
335
336
  } else {
336
337
  print(text)
337
338
  }
@@ -339,12 +340,12 @@ public enum ModelsCommand {
339
340
 
340
341
  private static func colorizeByUsage(_ text: String, tokens: Int) -> String {
341
342
  let code = switch tokens {
342
- case 1_000_000...: "35" // magenta - very high
343
- case 500_000...: "33" // yellow - high
344
- case 100_000...: "32" // green - medium
345
- default: "0" // default
343
+ case 1_000_000...: "35" // magenta - very high
344
+ case 500_000...: "33" // yellow - high
345
+ case 100_000...: "32" // green - medium
346
+ default: "0" // default
346
347
  }
347
- return ansi(code, text)
348
+ return self.ansi(code, text)
348
349
  }
349
350
 
350
351
  private static func ansi(_ code: String, _ text: String) -> String {