@sriinnu/runic 1.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 (584) hide show
  1. package/.swiftformat +50 -0
  2. package/.swiftlint.yml +160 -0
  3. package/CHANGELOG.md +307 -0
  4. package/CONTRIBUTING.md +456 -0
  5. package/Icon.icns +0 -0
  6. package/Icon.icon/Assets/runic.png +0 -0
  7. package/Icon.icon/icon.json +36 -0
  8. package/LICENSE +21 -0
  9. package/Package.resolved +51 -0
  10. package/Package.swift +136 -0
  11. package/Packages/Helix/LICENSE +21 -0
  12. package/Packages/Helix/Package.swift +29 -0
  13. package/Packages/Helix/README.md +976 -0
  14. package/Packages/Helix/Sources/Helix/Binding.swift +111 -0
  15. package/Packages/Helix/Sources/Helix/CommandParser.swift +160 -0
  16. package/Packages/Helix/Sources/Helix/CommandSignature.swift +117 -0
  17. package/Packages/Helix/Sources/Helix/ExpressibleFromArgument.swift +72 -0
  18. package/Packages/Helix/Sources/Helix/HelpGenerator.swift +175 -0
  19. package/Packages/Helix/Sources/Helix/NameSpecification.swift +98 -0
  20. package/Packages/Helix/Sources/Helix/ParsableCommand.swift +204 -0
  21. package/Packages/Helix/Sources/Helix/Platform/DarwinPlatformContext.swift +44 -0
  22. package/Packages/Helix/Sources/Helix/Platform/LinuxPlatformContext.swift +34 -0
  23. package/Packages/Helix/Sources/Helix/Platform/PlatformContext+Default.swift +91 -0
  24. package/Packages/Helix/Sources/Helix/Platform/PlatformContext.swift +94 -0
  25. package/Packages/Helix/Sources/Helix/Platform/PlatformPath.swift +167 -0
  26. package/Packages/Helix/Sources/Helix/Platform/Stdio.swift +99 -0
  27. package/Packages/Helix/Sources/Helix/Platform/WebPlatformContext.swift +146 -0
  28. package/Packages/Helix/Sources/Helix/Platform/WindowsPlatformContext.swift +97 -0
  29. package/Packages/Helix/Sources/Helix/Program.swift +204 -0
  30. package/Packages/Helix/Sources/Helix/PropertyWrappers.swift +367 -0
  31. package/Packages/Silo/LICENSE +21 -0
  32. package/Packages/Silo/Package.swift +34 -0
  33. package/Packages/Silo/README.md +466 -0
  34. package/Packages/Silo/Sources/Silo/BinaryCookiesReader.swift +169 -0
  35. package/Packages/Silo/Sources/Silo/BrowserCookieAnalytics.swift +365 -0
  36. package/Packages/Silo/Sources/Silo/BrowserCookieBackends.swift +594 -0
  37. package/Packages/Silo/Sources/Silo/BrowserCookieClient.swift +326 -0
  38. package/Packages/Silo/Sources/Silo/BrowserCookieExport.swift +154 -0
  39. package/Packages/Silo/Sources/Silo/BrowserCookieImport.swift +119 -0
  40. package/Packages/Silo/Sources/Silo/BrowserCookieMockStore.swift +121 -0
  41. package/Packages/Silo/Sources/Silo/BrowserCookieModels.swift +391 -0
  42. package/Packages/Silo/Sources/Silo/ChromiumCookieReader.swift +240 -0
  43. package/Packages/Silo/Sources/Silo/CryptoSupport.swift +86 -0
  44. package/Packages/Silo/Sources/Silo/FirefoxCookieReader.swift +172 -0
  45. package/Packages/Silo/Sources/Silo/LinuxChromiumCookieReader.swift +172 -0
  46. package/Packages/Silo/Sources/Silo/LinuxSecretService.swift +105 -0
  47. package/Packages/Silo/Sources/Silo/MacOSChromiumCookieReader.swift +191 -0
  48. package/Packages/Silo/Sources/Silo/SQLiteSnapshot.swift +41 -0
  49. package/Packages/Silo/Sources/Silo/WindowsChromiumCookieReader.swift +110 -0
  50. package/README.md +109 -0
  51. package/RuniciOS/App/RuniciOSApp.swift +105 -0
  52. package/RuniciOS/Core/iOSUsageStore.swift +192 -0
  53. package/RuniciOS/Views/ProviderDetailView.swift +312 -0
  54. package/RuniciOS/Views/ProviderListView.swift +228 -0
  55. package/RuniciOS/Widgets/LargeWidget.swift +367 -0
  56. package/RuniciOS/Widgets/LiveActivity.swift +342 -0
  57. package/RuniciOS/Widgets/LockScreenWidget.swift +273 -0
  58. package/RuniciOS/Widgets/MediumWidget.swift +370 -0
  59. package/RuniciOS/Widgets/RunicWidget.swift +274 -0
  60. package/RuniciOS/Widgets/SmallWidget.swift +281 -0
  61. package/RuniciOS/Widgets/WidgetModels.swift +285 -0
  62. package/RuniciOS/Widgets/WidgetTimeline.swift +270 -0
  63. package/Scripts/CREATION-SUMMARY.md +367 -0
  64. package/Scripts/DIRECTORY-STRUCTURE.md +358 -0
  65. package/Scripts/GETTING-STARTED-CHECKLIST.md +364 -0
  66. package/Scripts/INDEX.md +365 -0
  67. package/Scripts/QUICK-REFERENCE.md +164 -0
  68. package/Scripts/README-SCRIPTS.md +926 -0
  69. package/Scripts/build-android.sh +526 -0
  70. package/Scripts/build-ios.sh +529 -0
  71. package/Scripts/build-macos.sh +603 -0
  72. package/Scripts/build-windows.sh +504 -0
  73. package/Scripts/build_icon.sh +49 -0
  74. package/Scripts/changelog-to-html.sh +89 -0
  75. package/Scripts/check-release-assets.sh +10 -0
  76. package/Scripts/ci-config.yml +474 -0
  77. package/Scripts/compile_and_run.sh +219 -0
  78. package/Scripts/compile_and_run_adhoc.sh +4 -0
  79. package/Scripts/docs-list.mjs +119 -0
  80. package/Scripts/make_appcast.sh +58 -0
  81. package/Scripts/package_app.sh +409 -0
  82. package/Scripts/release-lib.sh +214 -0
  83. package/Scripts/release.sh +76 -0
  84. package/Scripts/setup-all.sh +387 -0
  85. package/Scripts/setup-ios.sh +404 -0
  86. package/Scripts/setup-react-native.sh +523 -0
  87. package/Scripts/sign-and-notarize.sh +122 -0
  88. package/Scripts/test_live_update.sh +38 -0
  89. package/Scripts/validate_changelog.sh +23 -0
  90. package/Scripts/verify_appcast.sh +92 -0
  91. package/Sources/Runic/About.swift +93 -0
  92. package/Sources/Runic/AppNotifications.swift +115 -0
  93. package/Sources/Runic/Controllers/StatusItemController+Actions.swift +657 -0
  94. package/Sources/Runic/Controllers/StatusItemController+Animation.swift +518 -0
  95. package/Sources/Runic/Controllers/StatusItemController+ChartSubmenus.swift +810 -0
  96. package/Sources/Runic/Controllers/StatusItemController+CustomProviders.swift +87 -0
  97. package/Sources/Runic/Controllers/StatusItemController+Menu.swift +1379 -0
  98. package/Sources/Runic/Controllers/StatusItemController+MenuCards.swift +337 -0
  99. package/Sources/Runic/Controllers/StatusItemController+MenuHelpers.swift +395 -0
  100. package/Sources/Runic/Controllers/StatusItemController.swift +360 -0
  101. package/Sources/Runic/Core/BudgetNotificationManager.swift +80 -0
  102. package/Sources/Runic/Core/Login/ClaudeLoginRunner.swift +103 -0
  103. package/Sources/Runic/Core/Login/CodexLoginRunner.swift +154 -0
  104. package/Sources/Runic/Core/Login/CursorLoginRunner.swift +206 -0
  105. package/Sources/Runic/Core/Login/GeminiLoginRunner.swift +95 -0
  106. package/Sources/Runic/Core/Rendering/IconRenderer.swift +1216 -0
  107. package/Sources/Runic/Core/Rendering/IconView.swift +120 -0
  108. package/Sources/Runic/Core/Rendering/ProviderBrandIcon.swift +71 -0
  109. package/Sources/Runic/Core/RunicAnimation.swift +53 -0
  110. package/Sources/Runic/Core/RunicColors.swift +73 -0
  111. package/Sources/Runic/Core/RunicCornerRadius.swift +15 -0
  112. package/Sources/Runic/Core/RunicSpacing.swift +68 -0
  113. package/Sources/Runic/Core/Stores/AuggieTokenStore.swift +143 -0
  114. package/Sources/Runic/Core/Stores/AzureOpenAITokenStore.swift +143 -0
  115. package/Sources/Runic/Core/Stores/CerebrasTokenStore.swift +143 -0
  116. package/Sources/Runic/Core/Stores/CohereTokenStore.swift +143 -0
  117. package/Sources/Runic/Core/Stores/CopilotTokenStore.swift +143 -0
  118. package/Sources/Runic/Core/Stores/CustomProviderStore.swift +158 -0
  119. package/Sources/Runic/Core/Stores/DeepSeekTokenStore.swift +143 -0
  120. package/Sources/Runic/Core/Stores/FireworksTokenStore.swift +143 -0
  121. package/Sources/Runic/Core/Stores/GroqTokenStore.swift +143 -0
  122. package/Sources/Runic/Core/Stores/KimiTokenStore.swift +143 -0
  123. package/Sources/Runic/Core/Stores/MiniMaxCookieHeaderStore.swift +143 -0
  124. package/Sources/Runic/Core/Stores/MiniMaxGroupIDStore.swift +143 -0
  125. package/Sources/Runic/Core/Stores/MiniMaxTokenStore.swift +143 -0
  126. package/Sources/Runic/Core/Stores/MistralTokenStore.swift +143 -0
  127. package/Sources/Runic/Core/Stores/OpenRouterTokenStore.swift +143 -0
  128. package/Sources/Runic/Core/Stores/PerplexityTokenStore.swift +143 -0
  129. package/Sources/Runic/Core/Stores/ProviderToggleStore.swift +30 -0
  130. package/Sources/Runic/Core/Stores/QwenTokenStore.swift +143 -0
  131. package/Sources/Runic/Core/Stores/SambaNovaTokenStore.swift +143 -0
  132. package/Sources/Runic/Core/Stores/SettingsStore.swift +1702 -0
  133. package/Sources/Runic/Core/Stores/TogetherTokenStore.swift +143 -0
  134. package/Sources/Runic/Core/Stores/UsageStore+Accessors.swift +20 -0
  135. package/Sources/Runic/Core/Stores/UsageStore+Status.swift +189 -0
  136. package/Sources/Runic/Core/Stores/UsageStore+TokenCost.swift +33 -0
  137. package/Sources/Runic/Core/Stores/UsageStore+WidgetSnapshot.swift +67 -0
  138. package/Sources/Runic/Core/Stores/UsageStore.swift +3564 -0
  139. package/Sources/Runic/Core/Stores/XAITokenStore.swift +143 -0
  140. package/Sources/Runic/Core/Stores/ZaiTokenStore.swift +143 -0
  141. package/Sources/Runic/Core/UsageExporter.swift +193 -0
  142. package/Sources/Runic/Date+RelativeDescription.swift +21 -0
  143. package/Sources/Runic/HiddenWindowView.swift +32 -0
  144. package/Sources/Runic/InstallOrigin.swift +9 -0
  145. package/Sources/Runic/KeyboardShortcuts+Names.swift +6 -0
  146. package/Sources/Runic/MouseLocationReader.swift +65 -0
  147. package/Sources/Runic/Notifications+Runic.swift +6 -0
  148. package/Sources/Runic/OpenAICreditsPurchaseWindowController.swift +503 -0
  149. package/Sources/Runic/ProviderRegistry.swift +100 -0
  150. package/Sources/Runic/ProviderSwitcherButtons.swift +267 -0
  151. package/Sources/Runic/Providers/Antigravity/AntigravityLoginFlow.swift +11 -0
  152. package/Sources/Runic/Providers/Antigravity/AntigravityProviderImplementation.swift +14 -0
  153. package/Sources/Runic/Providers/Auggie/AuggieProviderImplementation.swift +24 -0
  154. package/Sources/Runic/Providers/Azure/AzureProviderImplementation.swift +52 -0
  155. package/Sources/Runic/Providers/Bedrock/BedrockProviderImplementation.swift +42 -0
  156. package/Sources/Runic/Providers/Cerebras/CerebrasProviderImplementation.swift +24 -0
  157. package/Sources/Runic/Providers/Claude/ClaudeLoginFlow.swift +26 -0
  158. package/Sources/Runic/Providers/Claude/ClaudeProviderImplementation.swift +14 -0
  159. package/Sources/Runic/Providers/Codex/CodexLoginFlow.swift +18 -0
  160. package/Sources/Runic/Providers/Codex/CodexProviderImplementation.swift +15 -0
  161. package/Sources/Runic/Providers/Cohere/CohereProviderImplementation.swift +24 -0
  162. package/Sources/Runic/Providers/Copilot/CopilotLoginFlow.swift +193 -0
  163. package/Sources/Runic/Providers/Copilot/CopilotProviderImplementation.swift +110 -0
  164. package/Sources/Runic/Providers/Cursor/CursorLoginFlow.swift +28 -0
  165. package/Sources/Runic/Providers/Cursor/CursorProviderImplementation.swift +15 -0
  166. package/Sources/Runic/Providers/DeepSeek/DeepSeekProviderImplementation.swift +24 -0
  167. package/Sources/Runic/Providers/Factory/FactoryLoginFlow.swift +12 -0
  168. package/Sources/Runic/Providers/Factory/FactoryProviderImplementation.swift +15 -0
  169. package/Sources/Runic/Providers/Fireworks/FireworksProviderImplementation.swift +24 -0
  170. package/Sources/Runic/Providers/Gemini/GeminiLoginFlow.swift +20 -0
  171. package/Sources/Runic/Providers/Gemini/GeminiProviderImplementation.swift +15 -0
  172. package/Sources/Runic/Providers/Groq/GroqProviderImplementation.swift +24 -0
  173. package/Sources/Runic/Providers/Kimi/KimiProviderImplementation.swift +24 -0
  174. package/Sources/Runic/Providers/MiniMax/MiniMaxProviderImplementation.swift +32 -0
  175. package/Sources/Runic/Providers/Mistral/MistralProviderImplementation.swift +24 -0
  176. package/Sources/Runic/Providers/OpenRouter/OpenRouterProviderImplementation.swift +24 -0
  177. package/Sources/Runic/Providers/Perplexity/PerplexityProviderImplementation.swift +24 -0
  178. package/Sources/Runic/Providers/SambaNova/SambaNovaProviderImplementation.swift +24 -0
  179. package/Sources/Runic/Providers/Shared/ProviderCatalog.swift +15 -0
  180. package/Sources/Runic/Providers/Shared/ProviderImplementation.swift +48 -0
  181. package/Sources/Runic/Providers/Shared/ProviderImplementationRegistry.swift +66 -0
  182. package/Sources/Runic/Providers/Shared/ProviderLoginFlow.swift +12 -0
  183. package/Sources/Runic/Providers/Shared/ProviderSettingsDescriptors.swift +99 -0
  184. package/Sources/Runic/Providers/Shared/SystemSettingsLinks.swift +18 -0
  185. package/Sources/Runic/Providers/Together/TogetherProviderImplementation.swift +24 -0
  186. package/Sources/Runic/Providers/XAI/XAIProviderImplementation.swift +24 -0
  187. package/Sources/Runic/Providers/Zai/ZaiProviderImplementation.swift +24 -0
  188. package/Sources/Runic/Resources/ProviderIcon-antigravity.svg +2 -0
  189. package/Sources/Runic/Resources/ProviderIcon-auggie.svg +3 -0
  190. package/Sources/Runic/Resources/ProviderIcon-azure.svg +5 -0
  191. package/Sources/Runic/Resources/ProviderIcon-bedrock.svg +7 -0
  192. package/Sources/Runic/Resources/ProviderIcon-cerebras.svg +3 -0
  193. package/Sources/Runic/Resources/ProviderIcon-claude.svg +1 -0
  194. package/Sources/Runic/Resources/ProviderIcon-codex.svg +1 -0
  195. package/Sources/Runic/Resources/ProviderIcon-cohere.svg +3 -0
  196. package/Sources/Runic/Resources/ProviderIcon-copilot.svg +1 -0
  197. package/Sources/Runic/Resources/ProviderIcon-cursor.svg +3 -0
  198. package/Sources/Runic/Resources/ProviderIcon-deepseek.svg +4 -0
  199. package/Sources/Runic/Resources/ProviderIcon-factory.svg +3 -0
  200. package/Sources/Runic/Resources/ProviderIcon-fireworks.svg +3 -0
  201. package/Sources/Runic/Resources/ProviderIcon-gemini.svg +1 -0
  202. package/Sources/Runic/Resources/ProviderIcon-groq.svg +1 -0
  203. package/Sources/Runic/Resources/ProviderIcon-kimi.svg +4 -0
  204. package/Sources/Runic/Resources/ProviderIcon-minimax.svg +1 -0
  205. package/Sources/Runic/Resources/ProviderIcon-mistral.svg +5 -0
  206. package/Sources/Runic/Resources/ProviderIcon-openrouter.svg +7 -0
  207. package/Sources/Runic/Resources/ProviderIcon-perplexity.svg +4 -0
  208. package/Sources/Runic/Resources/ProviderIcon-qwen.svg +9 -0
  209. package/Sources/Runic/Resources/ProviderIcon-sambanova.svg +4 -0
  210. package/Sources/Runic/Resources/ProviderIcon-together.svg +5 -0
  211. package/Sources/Runic/Resources/ProviderIcon-vertexai.svg +17 -0
  212. package/Sources/Runic/Resources/ProviderIcon-xai.svg +3 -0
  213. package/Sources/Runic/Resources/ProviderIcon-zai.svg +5 -0
  214. package/Sources/Runic/Resources/RunicMenubarIcon.svg +7 -0
  215. package/Sources/Runic/RunicApp.swift +357 -0
  216. package/Sources/Runic/SessionQuotaNotifications.swift +58 -0
  217. package/Sources/Runic/UsagePaceText.swift +52 -0
  218. package/Sources/Runic/UsageProgressBar.swift +224 -0
  219. package/Sources/Runic/Utilities/DisplayLink.swift +96 -0
  220. package/Sources/Runic/Utilities/LoadingPattern.swift +60 -0
  221. package/Sources/Runic/Utilities/PerformanceConstants.swift +85 -0
  222. package/Sources/Runic/Views/Menu/AlertsMenuView.swift +256 -0
  223. package/Sources/Runic/Views/Menu/ChartPanelStyle.swift +22 -0
  224. package/Sources/Runic/Views/Menu/CostComparativeChartMenuView.swift +275 -0
  225. package/Sources/Runic/Views/Menu/CostHistoryChartMenuView.swift +377 -0
  226. package/Sources/Runic/Views/Menu/CreditsHistoryChartMenuView.swift +312 -0
  227. package/Sources/Runic/Views/Menu/EfficiencyMetricsMenuView.swift +312 -0
  228. package/Sources/Runic/Views/Menu/HeroStatCardsMenuView.swift +228 -0
  229. package/Sources/Runic/Views/Menu/HourlyActivityChartMenuView.swift +228 -0
  230. package/Sources/Runic/Views/Menu/InlineUsageChartView.swift +162 -0
  231. package/Sources/Runic/Views/Menu/MenuCardEntranceModifier.swift +64 -0
  232. package/Sources/Runic/Views/Menu/MenuCardSidebarView.swift +268 -0
  233. package/Sources/Runic/Views/Menu/MenuCardSkeletonView.swift +104 -0
  234. package/Sources/Runic/Views/Menu/MenuCardView.swift +1900 -0
  235. package/Sources/Runic/Views/Menu/MenuContent.swift +150 -0
  236. package/Sources/Runic/Views/Menu/MenuDescriptor.swift +369 -0
  237. package/Sources/Runic/Views/Menu/MenuHighlightStyle.swift +42 -0
  238. package/Sources/Runic/Views/Menu/ModelBreakdownMenuView.swift +235 -0
  239. package/Sources/Runic/Views/Menu/OverviewMenuView.swift +141 -0
  240. package/Sources/Runic/Views/Menu/ProjectBreakdownMenuView.swift +209 -0
  241. package/Sources/Runic/Views/Menu/ProjectBudgetMenuView.swift +220 -0
  242. package/Sources/Runic/Views/Menu/ProviderTabBarView.swift +88 -0
  243. package/Sources/Runic/Views/Menu/SubscriptionUtilizationChartMenuView.swift +201 -0
  244. package/Sources/Runic/Views/Menu/UsageBreakdownChartMenuView.swift +398 -0
  245. package/Sources/Runic/Views/Menu/UsageHeatmapMenuView.swift +232 -0
  246. package/Sources/Runic/Views/Menu/UsageTimelineChartMenuView.swift +417 -0
  247. package/Sources/Runic/Views/Menu/UsageWindowComparisonChartMenuView.swift +190 -0
  248. package/Sources/Runic/Views/Menu/WeeklyActivityChartMenuView.swift +132 -0
  249. package/Sources/Runic/Views/Performance/PerformanceDashboardView.swift +618 -0
  250. package/Sources/Runic/Views/Preferences/LiquidComponents.swift +305 -0
  251. package/Sources/Runic/Views/Preferences/PreferencesAboutPane.swift +271 -0
  252. package/Sources/Runic/Views/Preferences/PreferencesAdvancedPane.swift +268 -0
  253. package/Sources/Runic/Views/Preferences/PreferencesAlertsPane.swift +422 -0
  254. package/Sources/Runic/Views/Preferences/PreferencesAnalyticsPane.swift +641 -0
  255. package/Sources/Runic/Views/Preferences/PreferencesBudgetsPane.swift +344 -0
  256. package/Sources/Runic/Views/Preferences/PreferencesComponents.swift +230 -0
  257. package/Sources/Runic/Views/Preferences/PreferencesCustomProvidersPane.swift +322 -0
  258. package/Sources/Runic/Views/Preferences/PreferencesDebugPane.swift +469 -0
  259. package/Sources/Runic/Views/Preferences/PreferencesGeneralPane.swift +231 -0
  260. package/Sources/Runic/Views/Preferences/PreferencesHelpPane.swift +50 -0
  261. package/Sources/Runic/Views/Preferences/PreferencesIntegrationsPane.swift +497 -0
  262. package/Sources/Runic/Views/Preferences/PreferencesPerformancePane.swift +288 -0
  263. package/Sources/Runic/Views/Preferences/PreferencesProvidersPane.swift +3435 -0
  264. package/Sources/Runic/Views/Preferences/PreferencesSelection.swift +25 -0
  265. package/Sources/Runic/Views/Preferences/PreferencesSyncPane.swift +59 -0
  266. package/Sources/Runic/Views/Preferences/PreferencesView.swift +206 -0
  267. package/Sources/Runic/Views/Rating/QualityRatingView.swift +238 -0
  268. package/Sources/Runic/Views/Team/TeamDashboardView.swift +371 -0
  269. package/Sources/Runic/Views/Team/TeamInviteSheet.swift +175 -0
  270. package/Sources/Runic/Views/Team/TeamManagementView.swift +761 -0
  271. package/Sources/Runic/Views/Team/TeamMemberRow.swift +181 -0
  272. package/Sources/RunicCLI/CLIEntry.swift +942 -0
  273. package/Sources/RunicCLI/CLIRenderer.swift +87 -0
  274. package/Sources/RunicCLI/Commands/EnhancedUsageCommand.swift +588 -0
  275. package/Sources/RunicCLI/Commands/ModelsCommand.swift +362 -0
  276. package/Sources/RunicCLI/Commands/ProjectsCommand.swift +439 -0
  277. package/Sources/RunicCLI/Commands/ResetCommand.swift +429 -0
  278. package/Sources/RunicCLI/Commands/UsageLedgerSourceFactory.swift +168 -0
  279. package/Sources/RunicClaudeWatchdog/main.swift +122 -0
  280. package/Sources/RunicClaudeWebProbe/main.swift +62 -0
  281. package/Sources/RunicCore/AlertRuleStore.swift +187 -0
  282. package/Sources/RunicCore/BrowserCookieImportOrder.swift +25 -0
  283. package/Sources/RunicCore/CopilotUsageModels.swift +84 -0
  284. package/Sources/RunicCore/CostUsageFetcher.swift +119 -0
  285. package/Sources/RunicCore/CostUsageModels.swift +479 -0
  286. package/Sources/RunicCore/CreditsModels.swift +50 -0
  287. package/Sources/RunicCore/CustomProviders/CustomProviderModels.swift +269 -0
  288. package/Sources/RunicCore/CustomProviders/GenericProviderFetcher.swift +622 -0
  289. package/Sources/RunicCore/CustomProviders/ProviderTemplates.swift +500 -0
  290. package/Sources/RunicCore/Host/PTY/TTYCommandRunner.swift +679 -0
  291. package/Sources/RunicCore/Host/Process/SubprocessRunner.swift +135 -0
  292. package/Sources/RunicCore/Integrations/GitHubIntegration.swift +173 -0
  293. package/Sources/RunicCore/Logging/JSONStderrLogHandler.swift +79 -0
  294. package/Sources/RunicCore/Logging/OSLogLogHandler.swift +86 -0
  295. package/Sources/RunicCore/Logging/RunicLog.swift +123 -0
  296. package/Sources/RunicCore/Models/EnhancedUsageModels.swift +371 -0
  297. package/Sources/RunicCore/OpenAIDashboardModels.swift +210 -0
  298. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardBrowserCookieImporter.swift +676 -0
  299. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardFetcher.swift +492 -0
  300. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardNavigationDelegate.swift +51 -0
  301. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardParser.swift +483 -0
  302. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardScrapeScript.swift +558 -0
  303. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardWebViewCache.swift +204 -0
  304. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardWebsiteDataStore.swift +78 -0
  305. package/Sources/RunicCore/PathEnvironment.swift +482 -0
  306. package/Sources/RunicCore/Performance/PerformanceModels.swift +371 -0
  307. package/Sources/RunicCore/Performance/PerformanceStorageImpl.swift +409 -0
  308. package/Sources/RunicCore/Policy/UsagePolicyEngine.swift +178 -0
  309. package/Sources/RunicCore/ProjectBudgetStore.swift +99 -0
  310. package/Sources/RunicCore/ProviderCostSnapshot.swift +29 -0
  311. package/Sources/RunicCore/Providers/Antigravity/AntigravityProviderDescriptor.swift +66 -0
  312. package/Sources/RunicCore/Providers/Antigravity/AntigravityStatusProbe.swift +685 -0
  313. package/Sources/RunicCore/Providers/Auggie/AuggieProviderDescriptor.swift +83 -0
  314. package/Sources/RunicCore/Providers/Auggie/AuggieUsageFetcher.swift +142 -0
  315. package/Sources/RunicCore/Providers/Azure/AzureProviderDescriptor.swift +141 -0
  316. package/Sources/RunicCore/Providers/Azure/AzureUsageFetcher.swift +186 -0
  317. package/Sources/RunicCore/Providers/Bedrock/BedrockProviderDescriptor.swift +126 -0
  318. package/Sources/RunicCore/Providers/Bedrock/BedrockUsageFetcher.swift +168 -0
  319. package/Sources/RunicCore/Providers/Cerebras/CerebrasProviderDescriptor.swift +84 -0
  320. package/Sources/RunicCore/Providers/Cerebras/CerebrasUsageFetcher.swift +75 -0
  321. package/Sources/RunicCore/Providers/Claude/ClaudeCLISession.swift +332 -0
  322. package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthCredentials.swift +180 -0
  323. package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthUsageFetcher.swift +137 -0
  324. package/Sources/RunicCore/Providers/Claude/ClaudeProviderDescriptor.swift +207 -0
  325. package/Sources/RunicCore/Providers/Claude/ClaudeStatusProbe.swift +654 -0
  326. package/Sources/RunicCore/Providers/Claude/ClaudeUsageDataSource.swift +28 -0
  327. package/Sources/RunicCore/Providers/Claude/ClaudeUsageFetcher.swift +480 -0
  328. package/Sources/RunicCore/Providers/Claude/ClaudeWeb/ClaudeWebAPIFetcher.swift +780 -0
  329. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthCredentials.swift +146 -0
  330. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthUsageFetcher.swift +269 -0
  331. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexTokenRefresher.swift +100 -0
  332. package/Sources/RunicCore/Providers/Codex/CodexProviderDescriptor.swift +243 -0
  333. package/Sources/RunicCore/Providers/Codex/CodexStatusProbe.swift +125 -0
  334. package/Sources/RunicCore/Providers/Codex/CodexUsageDataSource.swift +24 -0
  335. package/Sources/RunicCore/Providers/Codex/CodexWebDashboardStrategy.swift +181 -0
  336. package/Sources/RunicCore/Providers/Cohere/CohereProviderDescriptor.swift +83 -0
  337. package/Sources/RunicCore/Providers/Cohere/CohereUsageFetcher.swift +85 -0
  338. package/Sources/RunicCore/Providers/Copilot/CopilotDeviceFlow.swift +123 -0
  339. package/Sources/RunicCore/Providers/Copilot/CopilotGitHubCLITokenReader.swift +114 -0
  340. package/Sources/RunicCore/Providers/Copilot/CopilotProviderDescriptor.swift +100 -0
  341. package/Sources/RunicCore/Providers/Copilot/CopilotUsageFetcher.swift +291 -0
  342. package/Sources/RunicCore/Providers/Copilot/CopilotVSCodeTokenReader.swift +386 -0
  343. package/Sources/RunicCore/Providers/Cursor/CursorProviderDescriptor.swift +65 -0
  344. package/Sources/RunicCore/Providers/Cursor/CursorStatusProbe.swift +594 -0
  345. package/Sources/RunicCore/Providers/DeepSeek/DeepSeekProviderDescriptor.swift +85 -0
  346. package/Sources/RunicCore/Providers/DeepSeek/DeepSeekUsageFetcher.swift +108 -0
  347. package/Sources/RunicCore/Providers/Factory/FactoryLocalStorageImporter.swift +398 -0
  348. package/Sources/RunicCore/Providers/Factory/FactoryProviderDescriptor.swift +65 -0
  349. package/Sources/RunicCore/Providers/Factory/FactoryStatusProbe.swift +1275 -0
  350. package/Sources/RunicCore/Providers/Fireworks/FireworksProviderDescriptor.swift +84 -0
  351. package/Sources/RunicCore/Providers/Fireworks/FireworksUsageFetcher.swift +75 -0
  352. package/Sources/RunicCore/Providers/Gemini/GeminiProviderDescriptor.swift +65 -0
  353. package/Sources/RunicCore/Providers/Gemini/GeminiStatusProbe.swift +835 -0
  354. package/Sources/RunicCore/Providers/Groq/GroqProviderDescriptor.swift +83 -0
  355. package/Sources/RunicCore/Providers/Groq/GroqUsageFetcher.swift +71 -0
  356. package/Sources/RunicCore/Providers/Kimi/KimiProviderDescriptor.swift +83 -0
  357. package/Sources/RunicCore/Providers/Kimi/KimiUsageFetcher.swift +77 -0
  358. package/Sources/RunicCore/Providers/MiniMax/MiniMaxProviderDescriptor.swift +92 -0
  359. package/Sources/RunicCore/Providers/MiniMax/MiniMaxSettingsReader.swift +54 -0
  360. package/Sources/RunicCore/Providers/MiniMax/MiniMaxUsageFetcher.swift +171 -0
  361. package/Sources/RunicCore/Providers/MiniMax/MiniMaxWebUsageFetcher.swift +911 -0
  362. package/Sources/RunicCore/Providers/Mistral/MistralProviderDescriptor.swift +84 -0
  363. package/Sources/RunicCore/Providers/Mistral/MistralUsageFetcher.swift +75 -0
  364. package/Sources/RunicCore/Providers/OpenRouter/OpenRouterProviderDescriptor.swift +87 -0
  365. package/Sources/RunicCore/Providers/OpenRouter/OpenRouterUsageFetcher.swift +207 -0
  366. package/Sources/RunicCore/Providers/Perplexity/PerplexityProviderDescriptor.swift +84 -0
  367. package/Sources/RunicCore/Providers/Perplexity/PerplexityUsageFetcher.swift +75 -0
  368. package/Sources/RunicCore/Providers/ProviderBranding.swift +25 -0
  369. package/Sources/RunicCore/Providers/ProviderCLIConfig.swift +17 -0
  370. package/Sources/RunicCore/Providers/ProviderDescriptor.swift +129 -0
  371. package/Sources/RunicCore/Providers/ProviderFetchPlan.swift +263 -0
  372. package/Sources/RunicCore/Providers/ProviderSettingsSnapshot.swift +98 -0
  373. package/Sources/RunicCore/Providers/ProviderTokenResolver.swift +501 -0
  374. package/Sources/RunicCore/Providers/ProviderVersionDetector.swift +68 -0
  375. package/Sources/RunicCore/Providers/Providers.swift +184 -0
  376. package/Sources/RunicCore/Providers/Qwen/QwenProviderDescriptor.swift +84 -0
  377. package/Sources/RunicCore/Providers/Qwen/QwenSettingsReader.swift +30 -0
  378. package/Sources/RunicCore/Providers/Qwen/QwenUsageStats.swift +317 -0
  379. package/Sources/RunicCore/Providers/SambaNova/SambaNovaProviderDescriptor.swift +84 -0
  380. package/Sources/RunicCore/Providers/SambaNova/SambaNovaUsageFetcher.swift +75 -0
  381. package/Sources/RunicCore/Providers/Together/TogetherProviderDescriptor.swift +83 -0
  382. package/Sources/RunicCore/Providers/Together/TogetherUsageFetcher.swift +75 -0
  383. package/Sources/RunicCore/Providers/VertexAI/VertexAIProviderDescriptor.swift +123 -0
  384. package/Sources/RunicCore/Providers/VertexAI/VertexAISettingsReader.swift +48 -0
  385. package/Sources/RunicCore/Providers/VertexAI/VertexAIUsageFetcher.swift +144 -0
  386. package/Sources/RunicCore/Providers/XAI/XAIProviderDescriptor.swift +83 -0
  387. package/Sources/RunicCore/Providers/XAI/XAIUsageFetcher.swift +75 -0
  388. package/Sources/RunicCore/Providers/Zai/ZaiProviderDescriptor.swift +72 -0
  389. package/Sources/RunicCore/Providers/Zai/ZaiSettingsReader.swift +41 -0
  390. package/Sources/RunicCore/Providers/Zai/ZaiUsageStats.swift +724 -0
  391. package/Sources/RunicCore/Sync/BackgroundSyncManager.swift +385 -0
  392. package/Sources/RunicCore/Sync/SyncConflictResolver.swift +310 -0
  393. package/Sources/RunicCore/Sync/SyncProtocol.swift +288 -0
  394. package/Sources/RunicCore/Sync/SyncRecord.swift +405 -0
  395. package/Sources/RunicCore/Sync/SyncUsageExample.swift +294 -0
  396. package/Sources/RunicCore/Sync/TeamSyncRecords.swift +775 -0
  397. package/Sources/RunicCore/Sync/iCloudSyncEngine.swift +333 -0
  398. package/Sources/RunicCore/Team/TeamModels.swift +583 -0
  399. package/Sources/RunicCore/Team/TeamShowbackExporter.swift +495 -0
  400. package/Sources/RunicCore/Team/TeamStore.swift +792 -0
  401. package/Sources/RunicCore/TextParsing.swift +55 -0
  402. package/Sources/RunicCore/UsageFetcher.swift +694 -0
  403. package/Sources/RunicCore/UsageFormatter.swift +410 -0
  404. package/Sources/RunicCore/UsageLedger/ClaudeUsageLogSource.swift +329 -0
  405. package/Sources/RunicCore/UsageLedger/CodexUsageLogSource.swift +448 -0
  406. package/Sources/RunicCore/UsageLedger/OTelGenAILedgerAdapter.swift +550 -0
  407. package/Sources/RunicCore/UsageLedger/UsageLedger.swift +29 -0
  408. package/Sources/RunicCore/UsageLedger/UsageLedgerAggregator.swift +660 -0
  409. package/Sources/RunicCore/UsageLedger/UsageLedgerInsightsAdvisor.swift +209 -0
  410. package/Sources/RunicCore/UsageLedger/UsageLedgerModels.swift +417 -0
  411. package/Sources/RunicCore/UsageLedger/UsageLedgerProjectIdentity.swift +245 -0
  412. package/Sources/RunicCore/UsagePace.swift +81 -0
  413. package/Sources/RunicCore/Vendored/CostUsage/CostUsageCache.swift +73 -0
  414. package/Sources/RunicCore/Vendored/CostUsage/CostUsageJsonl.swift +74 -0
  415. package/Sources/RunicCore/Vendored/CostUsage/CostUsagePricing.swift +208 -0
  416. package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner+Claude.swift +455 -0
  417. package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner+Timestamp.swift +132 -0
  418. package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner.swift +589 -0
  419. package/Sources/RunicCore/WidgetSnapshot.swift +183 -0
  420. package/Sources/RunicMacroSupport/ProviderRegistrationMacros.swift +14 -0
  421. package/Sources/RunicMacros/ProviderRegistrationMacros.swift +216 -0
  422. package/Sources/RunicWidget/RunicWidgetBundle.swift +79 -0
  423. package/Sources/RunicWidget/RunicWidgetProvider.swift +283 -0
  424. package/Sources/RunicWidget/RunicWidgetViews.swift +680 -0
  425. package/Tests/RunicTests/AntigravityStatusProbeTests.swift +50 -0
  426. package/Tests/RunicTests/AppDelegateTests.swift +43 -0
  427. package/Tests/RunicTests/BrowserCookieOrderLabelTests.swift +22 -0
  428. package/Tests/RunicTests/CLIArgumentParsingTests.swift +70 -0
  429. package/Tests/RunicTests/CLICostTests.swift +65 -0
  430. package/Tests/RunicTests/CLIProviderSelectionTests.swift +22 -0
  431. package/Tests/RunicTests/CLISnapshotTests.swift +72 -0
  432. package/Tests/RunicTests/CLIWebFallbackTests.swift +58 -0
  433. package/Tests/RunicTests/ClaudeOAuthTests.swift +164 -0
  434. package/Tests/RunicTests/ClaudeResilienceTests.swift +30 -0
  435. package/Tests/RunicTests/ClaudeUsageTests.swift +370 -0
  436. package/Tests/RunicTests/CodexOAuthTests.swift +122 -0
  437. package/Tests/RunicTests/CodexUsageLogSourceTests.swift +82 -0
  438. package/Tests/RunicTests/CopilotTokenResolverTests.swift +75 -0
  439. package/Tests/RunicTests/CopilotVSCodeTokenReaderTests.swift +75 -0
  440. package/Tests/RunicTests/CostUsageDecodingTests.swift +394 -0
  441. package/Tests/RunicTests/CostUsagePricingTests.swift +50 -0
  442. package/Tests/RunicTests/CostUsageScannerTests.swift +700 -0
  443. package/Tests/RunicTests/CursorStatusProbeTests.swift +323 -0
  444. package/Tests/RunicTests/FactoryStatusProbeTests.swift +69 -0
  445. package/Tests/RunicTests/GeminiAPITestHelpers.swift +94 -0
  446. package/Tests/RunicTests/GeminiLoginAlertTests.swift +28 -0
  447. package/Tests/RunicTests/GeminiStatusProbeAPITests.swift +283 -0
  448. package/Tests/RunicTests/GeminiStatusProbePlanTests.swift +279 -0
  449. package/Tests/RunicTests/GeminiStatusProbeTests.swift +233 -0
  450. package/Tests/RunicTests/GeminiTestEnvironment.swift +87 -0
  451. package/Tests/RunicTests/GoogleWorkspaceStatusTests.swift +73 -0
  452. package/Tests/RunicTests/InstallOriginTests.swift +18 -0
  453. package/Tests/RunicTests/KeyboardShortcutsBundleTests.swift +9 -0
  454. package/Tests/RunicTests/LiveAccountTests.swift +24 -0
  455. package/Tests/RunicTests/LoadingPatternTests.swift +35 -0
  456. package/Tests/RunicTests/MenuCardModelTests.swift +545 -0
  457. package/Tests/RunicTests/MiniMaxCookieHeaderStoreTestSupport.swift +8 -0
  458. package/Tests/RunicTests/MiniMaxGroupIDStoreTestSupport.swift +8 -0
  459. package/Tests/RunicTests/MiniMaxParsingTests.swift +68 -0
  460. package/Tests/RunicTests/MiniMaxTokenStoreTestSupport.swift +8 -0
  461. package/Tests/RunicTests/OTelGenAILedgerAdapterTests.swift +112 -0
  462. package/Tests/RunicTests/OpenAIDashboardBrowserCookieImporterTests.swift +17 -0
  463. package/Tests/RunicTests/OpenAIDashboardFetcherCreditsWaitTests.swift +75 -0
  464. package/Tests/RunicTests/OpenAIDashboardOffscreenHostTests.swift +27 -0
  465. package/Tests/RunicTests/OpenAIDashboardParserTests.swift +134 -0
  466. package/Tests/RunicTests/OpenAIWebAccountSwitchTests.swift +53 -0
  467. package/Tests/RunicTests/OpenRouterTokenStoreTestSupport.swift +92 -0
  468. package/Tests/RunicTests/PathBuilderTests.swift +237 -0
  469. package/Tests/RunicTests/ProviderFetchPipelineTests.swift +160 -0
  470. package/Tests/RunicTests/ProviderIconResourcesTests.swift +38 -0
  471. package/Tests/RunicTests/ProviderMetadataStatusLinkTests.swift +16 -0
  472. package/Tests/RunicTests/ProviderRegistryTests.swift +29 -0
  473. package/Tests/RunicTests/ProviderSettingsDescriptorTests.swift +202 -0
  474. package/Tests/RunicTests/ProviderToggleStoreTests.swift +51 -0
  475. package/Tests/RunicTests/RunicTests.swift +120 -0
  476. package/Tests/RunicTests/SessionQuotaNotificationLogicTests.swift +36 -0
  477. package/Tests/RunicTests/SettingsStoreTests.swift +161 -0
  478. package/Tests/RunicTests/StatusItemAnimationTests.swift +49 -0
  479. package/Tests/RunicTests/StatusMenuTests.swift +434 -0
  480. package/Tests/RunicTests/StatusProbeTests.swift +377 -0
  481. package/Tests/RunicTests/SubprocessRunnerTests.swift +20 -0
  482. package/Tests/RunicTests/SubscriptionDetectionTests.swift +65 -0
  483. package/Tests/RunicTests/TTYCommandRunnerTests.swift +148 -0
  484. package/Tests/RunicTests/TTYIntegrationTests.swift +41 -0
  485. package/Tests/RunicTests/TeamShowbackExporterTests.swift +159 -0
  486. package/Tests/RunicTests/TextParsingTests.swift +12 -0
  487. package/Tests/RunicTests/UsageFormatterTests.swift +112 -0
  488. package/Tests/RunicTests/UsageLedgerAnomalyDetectionTests.swift +172 -0
  489. package/Tests/RunicTests/UsageLedgerForecastTests.swift +213 -0
  490. package/Tests/RunicTests/UsageLedgerInsightsAdvisorTests.swift +83 -0
  491. package/Tests/RunicTests/UsageLedgerProjectNameTests.swift +170 -0
  492. package/Tests/RunicTests/UsagePaceTests.swift +77 -0
  493. package/Tests/RunicTests/UsagePaceTextTests.swift +109 -0
  494. package/Tests/RunicTests/UsagePolicyEngineTests.swift +91 -0
  495. package/Tests/RunicTests/WidgetSnapshotTests.swift +45 -0
  496. package/Tests/RunicTests/ZaiProviderTests.swift +61 -0
  497. package/Tests/RunicTests/ZaiTokenStoreTestSupport.swift +6 -0
  498. package/TestsLinux/PlatformGatingTests.swift +46 -0
  499. package/appcast.xml +105 -0
  500. package/assets/logo-concept-stack.svg +24 -0
  501. package/assets/logo-minimal-bars.svg +15 -0
  502. package/assets/logo.svg +20 -0
  503. package/assets/logo2.svg +43 -0
  504. package/bin/docs-list +5 -0
  505. package/bin/install-runic-cli.sh +32 -0
  506. package/build-and-run.sh +369 -0
  507. package/docs/.nojekyll +1 -0
  508. package/docs/CNAME +1 -0
  509. package/docs/antigravity.md +75 -0
  510. package/docs/architecture.md +32 -0
  511. package/docs/claude.md +93 -0
  512. package/docs/cli-commands/integration_guide.md +371 -0
  513. package/docs/cli-commands/quick_reference.md +362 -0
  514. package/docs/cli-commands/readme.md +361 -0
  515. package/docs/cli.md +156 -0
  516. package/docs/cloudkit_sync_guide.md +495 -0
  517. package/docs/codebase_review.md +288 -0
  518. package/docs/codex-oauth.md +635 -0
  519. package/docs/codex.md +104 -0
  520. package/docs/codexbar.png +0 -0
  521. package/docs/copilot.md +44 -0
  522. package/docs/cursor.md +46 -0
  523. package/docs/design/designcomparisonchart.md +510 -0
  524. package/docs/design/implementationguide.md +792 -0
  525. package/docs/design/menubaricondesignconcepts.md +796 -0
  526. package/docs/design/mockups/hybridiconconcept.svg +62 -0
  527. package/docs/design/mockups/infinityiconconcept.svg +41 -0
  528. package/docs/design/mockups/infinityiconstates.svg +129 -0
  529. package/docs/design/mockups/wavelogorefined.svg +48 -0
  530. package/docs/design/quick_summary.md +426 -0
  531. package/docs/design/readme.md +478 -0
  532. package/docs/design/sizespecifications.md +575 -0
  533. package/docs/design-system.md +836 -0
  534. package/docs/factory.md +103 -0
  535. package/docs/gemini.md +73 -0
  536. package/docs/icon.md +37 -0
  537. package/docs/icon.png +0 -0
  538. package/docs/index.html +175 -0
  539. package/docs/keychain_fix.md +274 -0
  540. package/docs/minimax.md +71 -0
  541. package/docs/packaging.md +25 -0
  542. package/docs/progress-bar-improvements.md +240 -0
  543. package/docs/progress-bar-quick-reference.md +283 -0
  544. package/docs/progress-bar-technical-details.md +432 -0
  545. package/docs/progress-bar-visual-test.swift +375 -0
  546. package/docs/provider.md +202 -0
  547. package/docs/providers.md +86 -0
  548. package/docs/refactor/macros.md +35 -0
  549. package/docs/refresh-loop.md +22 -0
  550. package/docs/releasing-homebrew.md +35 -0
  551. package/docs/releasing.md +121 -0
  552. package/docs/research/concrete_todo_2026-02-22.md +47 -0
  553. package/docs/research/core-feature-research.md +248 -0
  554. package/docs/research/feature_uiux_roadmap_2026-02-22.md +202 -0
  555. package/docs/research/parity_matrix.md +49 -0
  556. package/docs/research/provider_expansion_candidates_2026-02-22.md +80 -0
  557. package/docs/research/provider_model_token_project_matrix_2026-02-23.md +46 -0
  558. package/docs/research/release_gate_checklist.md +57 -0
  559. package/docs/site.css +505 -0
  560. package/docs/sparkle.md +28 -0
  561. package/docs/status.md +28 -0
  562. package/docs/sync/implementation.md +393 -0
  563. package/docs/sync/readme.md +317 -0
  564. package/docs/sync_files_summary.md +391 -0
  565. package/docs/sync_quick_reference.md +225 -0
  566. package/docs/todo.md +11 -0
  567. package/docs/ui.md +29 -0
  568. package/docs/web-integration.md +9 -0
  569. package/docs/widgets.md +85 -0
  570. package/docs/workflows/error-handling-improvements.md +434 -0
  571. package/docs/workflows/folder_structure.md +299 -0
  572. package/docs/workflows/loading_states.md +446 -0
  573. package/docs/workflows/loading_states_examples.md +565 -0
  574. package/docs/workflows/loading_states_flow.md +430 -0
  575. package/docs/workflows/performance_optimizations.md +457 -0
  576. package/docs/workflows/phase1-cli-testing-report.md +313 -0
  577. package/docs/workflows/quick_reference.md +228 -0
  578. package/docs/workflows/readme.md +59 -0
  579. package/docs/workflows/recent_improvements.md +275 -0
  580. package/docs/workflows/sync_enablement_summary.md +400 -0
  581. package/docs/zai.md +43 -0
  582. package/package.json +36 -0
  583. package/runic.png +0 -0
  584. package/version.env +2 -0
@@ -0,0 +1,83 @@
1
+ import RunicMacroSupport
2
+ import Foundation
3
+
4
+ @ProviderDescriptorRegistration
5
+ @ProviderDescriptorDefinition
6
+ public enum GroqProviderDescriptor {
7
+ static func makeDescriptor() -> ProviderDescriptor {
8
+ ProviderDescriptor(
9
+ id: .groq,
10
+ metadata: ProviderMetadata(
11
+ id: .groq,
12
+ displayName: "Groq",
13
+ sessionLabel: "Models",
14
+ weeklyLabel: "",
15
+ opusLabel: nil,
16
+ supportsOpus: false,
17
+ supportsCredits: false,
18
+ creditsHint: "",
19
+ toggleTitle: "Show Groq usage",
20
+ cliName: "groq",
21
+ defaultEnabled: false,
22
+ isPrimaryProvider: false,
23
+ usesAccountFallback: false,
24
+ dashboardURL: "https://console.groq.com/usage",
25
+ statusPageURL: nil,
26
+ usageCoverage: ProviderUsageCoverage(
27
+ supportsModelBreakdown: true,
28
+ supportsTokenMetrics: false,
29
+ supportsProjectAttribution: false)),
30
+ branding: ProviderBranding(
31
+ iconStyle: .groq,
32
+ iconResourceName: "ProviderIcon-groq",
33
+ color: ProviderColor(red: 0 / 255, green: 200 / 255, blue: 150 / 255)),
34
+ tokenCost: ProviderTokenCostConfig(
35
+ supportsTokenCost: false,
36
+ noDataMessage: { "Groq cost summary is not supported." }),
37
+ fetchPlan: ProviderFetchPlan(
38
+ sourceModes: [.auto, .cli],
39
+ pipeline: ProviderFetchPipeline(resolveStrategies: { _ in [GroqAPIFetchStrategy()] })),
40
+ cli: ProviderCLIConfig(
41
+ name: "groq",
42
+ aliases: [],
43
+ versionDetector: nil))
44
+ }
45
+ }
46
+
47
+ struct GroqAPIFetchStrategy: ProviderFetchStrategy {
48
+ let id: String = "groq.api"
49
+ let kind: ProviderFetchKind = .apiToken
50
+
51
+ func isAvailable(_ context: ProviderFetchContext) async -> Bool {
52
+ Self.resolveToken(environment: context.env) != nil
53
+ }
54
+
55
+ func fetch(_ context: ProviderFetchContext) async throws -> ProviderFetchResult {
56
+ guard let apiKey = Self.resolveToken(environment: context.env) else {
57
+ throw GroqSettingsError.missingToken
58
+ }
59
+ let usage = try await GroqUsageFetcher.fetchModels(apiKey: apiKey)
60
+ return self.makeResult(
61
+ usage: usage.toUsageSnapshot(),
62
+ sourceLabel: "api")
63
+ }
64
+
65
+ func shouldFallback(on _: Error, context _: ProviderFetchContext) -> Bool {
66
+ false
67
+ }
68
+
69
+ private static func resolveToken(environment: [String: String]) -> String? {
70
+ ProviderTokenResolver.groqToken(environment: environment)
71
+ }
72
+ }
73
+
74
+ enum GroqSettingsError: LocalizedError, Sendable {
75
+ case missingToken
76
+
77
+ var errorDescription: String? {
78
+ switch self {
79
+ case .missingToken:
80
+ "Groq API key not found. Set it in Preferences → Providers → Groq or export GROQ_API_KEY."
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,71 @@
1
+ import Foundation
2
+
3
+ struct GroqModelsResponse: Decodable {
4
+ let data: [Model]?
5
+
6
+ struct Model: Decodable {
7
+ let id: String?
8
+ }
9
+ }
10
+
11
+ struct GroqUsageFetcher {
12
+ static let apiURL = URL(string: "https://api.groq.com/openai/v1/models")!
13
+
14
+ static func fetchModels(apiKey: String) async throws -> GroqModelsResponse {
15
+ var request = URLRequest(url: apiURL)
16
+ request.addValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
17
+ request.addValue("application/json", forHTTPHeaderField: "Content-Type")
18
+
19
+ let (data, response) = try await URLSession.shared.data(for: request)
20
+
21
+ guard let httpResponse = response as? HTTPURLResponse else {
22
+ throw GroqAPIError.invalidResponse
23
+ }
24
+
25
+ guard httpResponse.statusCode == 200 else {
26
+ throw GroqAPIError.httpError(statusCode: httpResponse.statusCode)
27
+ }
28
+
29
+ let decoder = JSONDecoder()
30
+ return try decoder.decode(GroqModelsResponse.self, from: data)
31
+ }
32
+ }
33
+
34
+ extension GroqModelsResponse {
35
+ func toUsageSnapshot() -> UsageSnapshot {
36
+ let models = (self.data ?? []).compactMap(\.id)
37
+ var summary = "Models available: \(models.count)"
38
+ let preview = models.prefix(3).joined(separator: ", ")
39
+ if !preview.isEmpty {
40
+ summary += " (\(preview))"
41
+ }
42
+
43
+ return UsageSnapshot(
44
+ primary: RateWindow(
45
+ usedPercent: 0,
46
+ windowMinutes: nil,
47
+ resetsAt: nil,
48
+ resetDescription: summary),
49
+ secondary: nil,
50
+ tertiary: nil,
51
+ updatedAt: Date(),
52
+ identity: nil)
53
+ }
54
+ }
55
+
56
+ enum GroqAPIError: LocalizedError, Sendable {
57
+ case invalidResponse
58
+ case httpError(statusCode: Int)
59
+ case decodingError
60
+
61
+ var errorDescription: String? {
62
+ switch self {
63
+ case .invalidResponse:
64
+ "Invalid response from Groq API"
65
+ case let .httpError(statusCode):
66
+ "Groq API returned status code \(statusCode)"
67
+ case .decodingError:
68
+ "Failed to decode Groq API response"
69
+ }
70
+ }
71
+ }
@@ -0,0 +1,83 @@
1
+ import RunicMacroSupport
2
+ import Foundation
3
+
4
+ @ProviderDescriptorRegistration
5
+ @ProviderDescriptorDefinition
6
+ public enum KimiProviderDescriptor {
7
+ static func makeDescriptor() -> ProviderDescriptor {
8
+ ProviderDescriptor(
9
+ id: .kimi,
10
+ metadata: ProviderMetadata(
11
+ id: .kimi,
12
+ displayName: "Kimi",
13
+ sessionLabel: "Models",
14
+ weeklyLabel: "",
15
+ opusLabel: nil,
16
+ supportsOpus: false,
17
+ supportsCredits: false,
18
+ creditsHint: "Shows model availability from Kimi API.",
19
+ toggleTitle: "Show Kimi usage",
20
+ cliName: "kimi",
21
+ defaultEnabled: false,
22
+ isPrimaryProvider: false,
23
+ usesAccountFallback: false,
24
+ dashboardURL: "https://platform.moonshot.ai/console",
25
+ statusPageURL: nil,
26
+ usageCoverage: ProviderUsageCoverage(
27
+ supportsModelBreakdown: true,
28
+ supportsTokenMetrics: false,
29
+ supportsProjectAttribution: false)),
30
+ branding: ProviderBranding(
31
+ iconStyle: .kimi,
32
+ iconResourceName: "ProviderIcon-kimi",
33
+ color: ProviderColor(red: 0 / 255, green: 129 / 255, blue: 255 / 255)),
34
+ tokenCost: ProviderTokenCostConfig(
35
+ supportsTokenCost: false,
36
+ noDataMessage: { "Kimi cost summary is not supported." }),
37
+ fetchPlan: ProviderFetchPlan(
38
+ sourceModes: [.auto, .cli],
39
+ pipeline: ProviderFetchPipeline(resolveStrategies: { _ in [KimiAPIFetchStrategy()] })),
40
+ cli: ProviderCLIConfig(
41
+ name: "kimi",
42
+ aliases: ["moonshot"],
43
+ versionDetector: nil))
44
+ }
45
+ }
46
+
47
+ struct KimiAPIFetchStrategy: ProviderFetchStrategy {
48
+ let id: String = "kimi.api"
49
+ let kind: ProviderFetchKind = .apiToken
50
+
51
+ func isAvailable(_ context: ProviderFetchContext) async -> Bool {
52
+ Self.resolveTokenResolution(environment: context.env) != nil
53
+ }
54
+
55
+ func fetch(_ context: ProviderFetchContext) async throws -> ProviderFetchResult {
56
+ guard let tokenRes = Self.resolveTokenResolution(environment: context.env) else {
57
+ throw KimiSettingsError.missingToken
58
+ }
59
+ let usage = try await KimiUsageFetcher.fetchModels(apiKey: tokenRes.token)
60
+ return self.makeResult(
61
+ usage: usage.toUsageSnapshot(),
62
+ sourceLabel: tokenRes.source.rawValue)
63
+ }
64
+
65
+ func shouldFallback(on _: Error, context _: ProviderFetchContext) -> Bool {
66
+ false
67
+ }
68
+
69
+ private static func resolveTokenResolution(environment: [String: String]) -> ProviderTokenResolution? {
70
+ ProviderTokenResolver.kimiResolution(environment: environment)
71
+ }
72
+ }
73
+
74
+ enum KimiSettingsError: LocalizedError, Sendable {
75
+ case missingToken
76
+
77
+ var errorDescription: String? {
78
+ switch self {
79
+ case .missingToken:
80
+ "Kimi API key not found. Set it in Preferences → Providers → Kimi or export KIMI_API_KEY."
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,77 @@
1
+ import Foundation
2
+
3
+ struct KimiModelsResponse: Decodable {
4
+ let data: [Model]?
5
+
6
+ struct Model: Decodable {
7
+ let id: String?
8
+ }
9
+ }
10
+
11
+ struct KimiUsageFetcher {
12
+ static let apiURL = URL(string: "https://api.moonshot.ai/v1/models")!
13
+ private static let requestTimeout: TimeInterval = 20
14
+
15
+ static func fetchModels(apiKey: String) async throws -> KimiModelsResponse {
16
+ var request = URLRequest(url: apiURL)
17
+ request.timeoutInterval = Self.requestTimeout
18
+ request.addValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
19
+ request.addValue("application/json", forHTTPHeaderField: "Content-Type")
20
+
21
+ let (data, response) = try await URLSession.shared.data(for: request)
22
+
23
+ guard let httpResponse = response as? HTTPURLResponse else {
24
+ throw KimiAPIError.invalidResponse
25
+ }
26
+
27
+ guard httpResponse.statusCode == 200 else {
28
+ let body = String(data: data, encoding: .utf8)?
29
+ .trimmingCharacters(in: .whitespacesAndNewlines)
30
+ throw KimiAPIError.httpError(
31
+ statusCode: httpResponse.statusCode,
32
+ body: body?.isEmpty == false ? body : nil)
33
+ }
34
+
35
+ let decoder = JSONDecoder()
36
+ return try decoder.decode(KimiModelsResponse.self, from: data)
37
+ }
38
+ }
39
+
40
+ extension KimiModelsResponse {
41
+ func toUsageSnapshot() -> UsageSnapshot {
42
+ let models = (self.data ?? []).compactMap(\.id)
43
+ var summary = "Models available: \(models.count)"
44
+ let preview = models.prefix(3).joined(separator: ", ")
45
+ if !preview.isEmpty {
46
+ summary += " (\(preview))"
47
+ }
48
+
49
+ return UsageSnapshot(
50
+ primary: RateWindow(
51
+ usedPercent: 0,
52
+ windowMinutes: nil,
53
+ resetsAt: nil,
54
+ resetDescription: summary),
55
+ secondary: nil,
56
+ tertiary: nil,
57
+ updatedAt: Date(),
58
+ identity: nil)
59
+ }
60
+ }
61
+
62
+ enum KimiAPIError: LocalizedError, Sendable {
63
+ case invalidResponse
64
+ case httpError(statusCode: Int, body: String?)
65
+
66
+ var errorDescription: String? {
67
+ switch self {
68
+ case .invalidResponse:
69
+ return "Invalid response from Kimi API"
70
+ case let .httpError(statusCode, body):
71
+ if let body, !body.isEmpty {
72
+ return "Kimi API returned status code \(statusCode): \(body)"
73
+ }
74
+ return "Kimi API returned status code \(statusCode)"
75
+ }
76
+ }
77
+ }
@@ -0,0 +1,92 @@
1
+ import RunicMacroSupport
2
+ import Foundation
3
+
4
+ @ProviderDescriptorRegistration
5
+ @ProviderDescriptorDefinition
6
+ public enum MiniMaxProviderDescriptor {
7
+ static func makeDescriptor() -> ProviderDescriptor {
8
+ ProviderDescriptor(
9
+ id: .minimax,
10
+ metadata: ProviderMetadata(
11
+ id: .minimax,
12
+ displayName: "MiniMax",
13
+ sessionLabel: "Plan",
14
+ weeklyLabel: "Cycle",
15
+ opusLabel: nil,
16
+ supportsOpus: false,
17
+ supportsCredits: false,
18
+ creditsHint: "",
19
+ toggleTitle: "Show MiniMax usage",
20
+ cliName: "minimax",
21
+ defaultEnabled: false,
22
+ isPrimaryProvider: false,
23
+ usesAccountFallback: false,
24
+ browserCookieOrder: ProviderBrowserCookieDefaults.defaultImportOrder,
25
+ dashboardURL: "https://platform.minimax.io/user-center/payment/coding-plan",
26
+ statusPageURL: nil,
27
+ usageCoverage: ProviderUsageCoverage(
28
+ supportsModelBreakdown: false,
29
+ supportsTokenMetrics: true,
30
+ supportsProjectAttribution: false)),
31
+ branding: ProviderBranding(
32
+ iconStyle: .minimax,
33
+ iconResourceName: "ProviderIcon-minimax",
34
+ color: ProviderColor(red: 50 / 255, green: 50 / 255, blue: 70 / 255)),
35
+ tokenCost: ProviderTokenCostConfig(
36
+ supportsTokenCost: false,
37
+ noDataMessage: { "MiniMax cost summary is not supported." }),
38
+ fetchPlan: ProviderFetchPlan(
39
+ sourceModes: [.auto, .api, .web],
40
+ pipeline: ProviderFetchPipeline(resolveStrategies: { _ in [MiniMaxAPIFetchStrategy(), MiniMaxWebFetchStrategy()] })),
41
+ cli: ProviderCLIConfig(
42
+ name: "minimax",
43
+ aliases: ["minimax-api"],
44
+ versionDetector: nil))
45
+ }
46
+ }
47
+
48
+ struct MiniMaxWebFetchStrategy: ProviderFetchStrategy {
49
+ let id: String = "minimax.web"
50
+ let kind: ProviderFetchKind = .web
51
+
52
+ func isAvailable(_: ProviderFetchContext) async -> Bool { true }
53
+
54
+ func fetch(_ context: ProviderFetchContext) async throws -> ProviderFetchResult {
55
+ let fetcher = MiniMaxWebUsageFetcher()
56
+ let result = try await fetcher.fetchUsage(
57
+ timeout: context.webTimeout,
58
+ logger: context.verbose ? { RunicLog.logger("minimax-web").debug("\($0)") } : nil)
59
+ return self.makeResult(
60
+ usage: result.usage,
61
+ sourceLabel: result.sourceLabel)
62
+ }
63
+
64
+ func shouldFallback(on _: Error, context _: ProviderFetchContext) -> Bool {
65
+ false
66
+ }
67
+ }
68
+
69
+ struct MiniMaxAPIFetchStrategy: ProviderFetchStrategy {
70
+ let id: String = "minimax.api"
71
+ let kind: ProviderFetchKind = .api
72
+
73
+ func isAvailable(_ context: ProviderFetchContext) async -> Bool {
74
+ ProviderTokenResolver.minimaxApiKeyResolution(environment: context.env) != nil
75
+ }
76
+
77
+ func fetch(_ context: ProviderFetchContext) async throws -> ProviderFetchResult {
78
+ guard let tokenRes = ProviderTokenResolver.minimaxApiKeyResolution(environment: context.env) else {
79
+ throw ProviderFetchError.missingCredentials
80
+ }
81
+
82
+ let snapshot = try await MiniMaxUsageFetcher.fetchUsage(apiKey: tokenRes.token)
83
+
84
+ return self.makeResult(
85
+ usage: snapshot.toUsageSnapshot(),
86
+ sourceLabel: "API")
87
+ }
88
+
89
+ func shouldFallback(on _: Error, context _: ProviderFetchContext) -> Bool {
90
+ true
91
+ }
92
+ }
@@ -0,0 +1,54 @@
1
+ import Foundation
2
+
3
+ public struct MiniMaxSettingsReader: Sendable {
4
+ private static let log = RunicLog.logger("minimax-settings")
5
+
6
+ public static let cookieKey = "MINIMAX_COOKIE"
7
+ public static let cookieHeaderKey = "MINIMAX_COOKIE_HEADER"
8
+ public static let groupIDKey = "MINIMAX_GROUP_ID"
9
+
10
+ public static func cookieHeader(
11
+ environment: [String: String] = ProcessInfo.processInfo.environment) -> String?
12
+ {
13
+ if let header = self.cleaned(environment[cookieHeaderKey]) { return header }
14
+ if let header = self.cleaned(environment[cookieKey]) { return header }
15
+ return nil
16
+ }
17
+
18
+ public static func groupID(
19
+ environment: [String: String] = ProcessInfo.processInfo.environment) -> String?
20
+ {
21
+ if let groupID = self.cleaned(environment[groupIDKey]) { return groupID }
22
+ return nil
23
+ }
24
+
25
+ static func cleaned(_ raw: String?) -> String? {
26
+ guard var value = raw?.trimmingCharacters(in: .whitespacesAndNewlines), !value.isEmpty else {
27
+ return nil
28
+ }
29
+
30
+ if (value.hasPrefix("\"") && value.hasSuffix("\"")) ||
31
+ (value.hasPrefix("'") && value.hasSuffix("'"))
32
+ {
33
+ value.removeFirst()
34
+ value.removeLast()
35
+ }
36
+
37
+ value = value.trimmingCharacters(in: .whitespacesAndNewlines)
38
+ return value.isEmpty ? nil : value
39
+ }
40
+ }
41
+
42
+ public enum MiniMaxSettingsError: LocalizedError, Sendable {
43
+ case missingCookieHeader
44
+ case missingGroupID
45
+
46
+ public var errorDescription: String? {
47
+ switch self {
48
+ case .missingCookieHeader:
49
+ "MiniMax session cookie not found. Set it in Settings → Providers → MiniMax or via MINIMAX_COOKIE."
50
+ case .missingGroupID:
51
+ "MiniMax Group ID not found. Set it in Settings → Providers → MiniMax or via MINIMAX_GROUP_ID."
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,171 @@
1
+ import Foundation
2
+ #if canImport(FoundationNetworking)
3
+ import FoundationNetworking
4
+ #endif
5
+
6
+ /// MiniMax quota/usage response structure (New API)
7
+ public struct MiniMaxQuotaResponse: Decodable {
8
+ public let baseResponse: MiniMaxBaseResponse
9
+ public let modelRemains: [MiniMaxModelRemain]?
10
+
11
+ enum CodingKeys: String, CodingKey {
12
+ case baseResponse = "base_resp"
13
+ case modelRemains = "model_remains"
14
+ }
15
+ }
16
+
17
+ public struct MiniMaxModelRemain: Decodable {
18
+ public let modelName: String
19
+ public let currentIntervalTotalCount: Int
20
+ public let currentIntervalUsageCount: Int
21
+
22
+ enum CodingKeys: String, CodingKey {
23
+ case modelName = "model_name"
24
+ case currentIntervalTotalCount = "current_interval_total_count"
25
+ case currentIntervalUsageCount = "current_interval_usage_count"
26
+ }
27
+ }
28
+
29
+ public struct MiniMaxBaseResponse: Decodable {
30
+ public let statusCode: Int
31
+ public let statusMsg: String
32
+
33
+ enum CodingKeys: String, CodingKey {
34
+ case statusCode = "status_code"
35
+ case statusMsg = "status_msg"
36
+ }
37
+ }
38
+
39
+ public struct MiniMaxUsageSnapshot: Sendable {
40
+ public let total: Int
41
+ public let used: Int
42
+ public let modelName: String?
43
+ public let updatedAt: Date
44
+
45
+ public init(total: Int, used: Int, modelName: String? = nil, updatedAt: Date) {
46
+ self.total = total
47
+ self.used = used
48
+ self.modelName = modelName
49
+ self.updatedAt = updatedAt
50
+ }
51
+
52
+ public var isValid: Bool {
53
+ self.total > 0
54
+ }
55
+ }
56
+
57
+ extension MiniMaxUsageSnapshot {
58
+ public func toUsageSnapshot() -> UsageSnapshot {
59
+ // "current_interval_usage_count" in the "remains" API is ambiguous.
60
+ // It likely represents "remaining_count" OR "used_count".
61
+ // Given total=4500, used=4500 (in the sample), consistent with "remains" response.
62
+ // But let's assume standard "usage" field naming means USED.
63
+ // If the user reports it shows 100% when new, we invert it.
64
+ // For now, let's map it as Used/Total.
65
+
66
+ let percent = self.total > 0 ? (Double(self.used) / Double(self.total)) * 100.0 : 0.0
67
+
68
+ let primary = RateWindow(
69
+ usedPercent: percent,
70
+ windowMinutes: 24 * 60,
71
+ resetsAt: nil,
72
+ resetDescription: "\(self.used) / \(self.total) (Please verify meaning)",
73
+ label: self.modelName?.trimmingCharacters(in: .whitespacesAndNewlines))
74
+
75
+ let identity = ProviderIdentitySnapshot(
76
+ providerID: .minimax,
77
+ accountEmail: nil,
78
+ accountOrganization: nil,
79
+ loginMethod: "api-key")
80
+
81
+ return UsageSnapshot(
82
+ primary: primary,
83
+ secondary: nil,
84
+ tertiary: nil,
85
+ providerCost: nil,
86
+ updatedAt: self.updatedAt,
87
+ identity: identity)
88
+ }
89
+ }
90
+
91
+ /// Fetches usage stats from the MiniMax API
92
+ public struct MiniMaxUsageFetcher: Sendable {
93
+ private static let log = RunicLog.logger("minimax-usage")
94
+
95
+ /// Corrected endpoint based on documentation
96
+ private static let quotaAPIURL = "https://platform.minimax.io/v1/api/openplatform/coding_plan/remains"
97
+
98
+ /// Fetches usage stats from MiniMax using the provided API key
99
+ /// GroupID is no longer required for this endpoint based on user input
100
+ public static func fetchUsage(apiKey: String) async throws -> MiniMaxUsageSnapshot {
101
+ guard !apiKey.isEmpty else {
102
+ throw MiniMaxUsageError.invalidCredentials
103
+ }
104
+
105
+ var request = URLRequest(url: URL(string: quotaAPIURL)!)
106
+ request.httpMethod = "GET"
107
+ request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
108
+ request.setValue("application/json", forHTTPHeaderField: "Content-Type")
109
+
110
+ let (data, response) = try await URLSession.shared.data(for: request)
111
+
112
+ guard let httpResponse = response as? HTTPURLResponse else {
113
+ throw MiniMaxUsageError.networkError("Invalid response")
114
+ }
115
+
116
+ guard httpResponse.statusCode == 200 else {
117
+ let errorMessage = String(data: data, encoding: .utf8) ?? "Unknown error"
118
+ Self.log.error("MiniMax API returned \(httpResponse.statusCode): \(errorMessage)")
119
+ throw MiniMaxUsageError.apiError("HTTP \(httpResponse.statusCode): \(errorMessage)")
120
+ }
121
+
122
+ // Log raw response for debugging
123
+ if let jsonString = String(data: data, encoding: .utf8) {
124
+ Self.log.debug("MiniMax API response: \(jsonString)")
125
+ }
126
+
127
+ let decoder = JSONDecoder()
128
+ do {
129
+ let apiResponse = try decoder.decode(MiniMaxQuotaResponse.self, from: data)
130
+
131
+ if apiResponse.baseResponse.statusCode != 0 {
132
+ throw MiniMaxUsageError.apiError(apiResponse.baseResponse.statusMsg)
133
+ }
134
+
135
+ guard let firstModel = apiResponse.modelRemains?.first else {
136
+ throw MiniMaxUsageError.parseFailed("No model quota found")
137
+ }
138
+
139
+ return MiniMaxUsageSnapshot(
140
+ total: firstModel.currentIntervalTotalCount,
141
+ used: firstModel.currentIntervalUsageCount,
142
+ modelName: firstModel.modelName,
143
+ updatedAt: Date())
144
+
145
+ } catch {
146
+ Self.log.error("MiniMax parsing error: \(error.localizedDescription)")
147
+ throw MiniMaxUsageError.parseFailed(error.localizedDescription)
148
+ }
149
+ }
150
+ }
151
+
152
+ /// Errors that can occur during MiniMax usage fetching
153
+ public enum MiniMaxUsageError: LocalizedError, Sendable {
154
+ case invalidCredentials
155
+ case networkError(String)
156
+ case apiError(String)
157
+ case parseFailed(String)
158
+
159
+ public var errorDescription: String? {
160
+ switch self {
161
+ case .invalidCredentials:
162
+ "Invalid MiniMax API credentials"
163
+ case let .networkError(message):
164
+ "MiniMax network error: \(message)"
165
+ case let .apiError(message):
166
+ "MiniMax API error: \(message)"
167
+ case let .parseFailed(message):
168
+ "Failed to parse MiniMax response: \(message)"
169
+ }
170
+ }
171
+ }