@sriinnu/runic 2.0.0 → 2.11.1

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 (610) hide show
  1. package/CHANGELOG.md +256 -0
  2. package/LICENSE +373 -21
  3. package/README.md +96 -89
  4. package/THIRD-PARTY-NOTICES.md +651 -0
  5. package/package.json +14 -4
  6. package/.swiftformat +0 -50
  7. package/.swiftlint.yml +0 -160
  8. package/CONTRIBUTING.md +0 -456
  9. package/Icon.icns +0 -0
  10. package/Icon.icon/Assets/runic.png +0 -0
  11. package/Icon.icon/icon.json +0 -36
  12. package/Package.resolved +0 -51
  13. package/Package.swift +0 -136
  14. package/Packages/Helix/LICENSE +0 -21
  15. package/Packages/Helix/Package.swift +0 -29
  16. package/Packages/Helix/README.md +0 -976
  17. package/Packages/Helix/Sources/Helix/Binding.swift +0 -111
  18. package/Packages/Helix/Sources/Helix/CommandParser.swift +0 -160
  19. package/Packages/Helix/Sources/Helix/CommandSignature.swift +0 -117
  20. package/Packages/Helix/Sources/Helix/ExpressibleFromArgument.swift +0 -72
  21. package/Packages/Helix/Sources/Helix/HelpGenerator.swift +0 -175
  22. package/Packages/Helix/Sources/Helix/NameSpecification.swift +0 -98
  23. package/Packages/Helix/Sources/Helix/ParsableCommand.swift +0 -204
  24. package/Packages/Helix/Sources/Helix/Platform/DarwinPlatformContext.swift +0 -44
  25. package/Packages/Helix/Sources/Helix/Platform/LinuxPlatformContext.swift +0 -34
  26. package/Packages/Helix/Sources/Helix/Platform/PlatformContext+Default.swift +0 -91
  27. package/Packages/Helix/Sources/Helix/Platform/PlatformContext.swift +0 -94
  28. package/Packages/Helix/Sources/Helix/Platform/PlatformPath.swift +0 -167
  29. package/Packages/Helix/Sources/Helix/Platform/Stdio.swift +0 -99
  30. package/Packages/Helix/Sources/Helix/Platform/WebPlatformContext.swift +0 -146
  31. package/Packages/Helix/Sources/Helix/Platform/WindowsPlatformContext.swift +0 -97
  32. package/Packages/Helix/Sources/Helix/Program.swift +0 -204
  33. package/Packages/Helix/Sources/Helix/PropertyWrappers.swift +0 -367
  34. package/Packages/Silo/LICENSE +0 -21
  35. package/Packages/Silo/Package.swift +0 -34
  36. package/Packages/Silo/README.md +0 -466
  37. package/Packages/Silo/Sources/Silo/BinaryCookiesReader.swift +0 -169
  38. package/Packages/Silo/Sources/Silo/BrowserCookieAnalytics.swift +0 -365
  39. package/Packages/Silo/Sources/Silo/BrowserCookieBackends.swift +0 -594
  40. package/Packages/Silo/Sources/Silo/BrowserCookieClient.swift +0 -326
  41. package/Packages/Silo/Sources/Silo/BrowserCookieExport.swift +0 -154
  42. package/Packages/Silo/Sources/Silo/BrowserCookieImport.swift +0 -119
  43. package/Packages/Silo/Sources/Silo/BrowserCookieMockStore.swift +0 -121
  44. package/Packages/Silo/Sources/Silo/BrowserCookieModels.swift +0 -391
  45. package/Packages/Silo/Sources/Silo/ChromiumCookieReader.swift +0 -240
  46. package/Packages/Silo/Sources/Silo/CryptoSupport.swift +0 -86
  47. package/Packages/Silo/Sources/Silo/FirefoxCookieReader.swift +0 -172
  48. package/Packages/Silo/Sources/Silo/LinuxChromiumCookieReader.swift +0 -172
  49. package/Packages/Silo/Sources/Silo/LinuxSecretService.swift +0 -105
  50. package/Packages/Silo/Sources/Silo/MacOSChromiumCookieReader.swift +0 -191
  51. package/Packages/Silo/Sources/Silo/SQLiteSnapshot.swift +0 -41
  52. package/Packages/Silo/Sources/Silo/WindowsChromiumCookieReader.swift +0 -110
  53. package/RuniciOS/App/RuniciOSApp.swift +0 -105
  54. package/RuniciOS/Core/RunicTypographyiOS.swift +0 -24
  55. package/RuniciOS/Core/iOSUsageStore.swift +0 -192
  56. package/RuniciOS/Views/ProviderDetailView.swift +0 -312
  57. package/RuniciOS/Views/ProviderListView.swift +0 -228
  58. package/RuniciOS/Widgets/LargeWidget.swift +0 -367
  59. package/RuniciOS/Widgets/LiveActivity.swift +0 -342
  60. package/RuniciOS/Widgets/LockScreenWidget.swift +0 -273
  61. package/RuniciOS/Widgets/MediumWidget.swift +0 -370
  62. package/RuniciOS/Widgets/RunicWidget.swift +0 -274
  63. package/RuniciOS/Widgets/SmallWidget.swift +0 -281
  64. package/RuniciOS/Widgets/WidgetModels.swift +0 -285
  65. package/RuniciOS/Widgets/WidgetTimeline.swift +0 -270
  66. package/Scripts/CREATION-SUMMARY.md +0 -367
  67. package/Scripts/DIRECTORY-STRUCTURE.md +0 -358
  68. package/Scripts/GETTING-STARTED-CHECKLIST.md +0 -364
  69. package/Scripts/INDEX.md +0 -365
  70. package/Scripts/QUICK-REFERENCE.md +0 -164
  71. package/Scripts/README-SCRIPTS.md +0 -926
  72. package/Scripts/build-android.sh +0 -526
  73. package/Scripts/build-ios.sh +0 -529
  74. package/Scripts/build-macos.sh +0 -603
  75. package/Scripts/build-windows.sh +0 -504
  76. package/Scripts/build_icon.sh +0 -49
  77. package/Scripts/changelog-to-html.sh +0 -89
  78. package/Scripts/check-release-assets.sh +0 -10
  79. package/Scripts/ci-config.yml +0 -474
  80. package/Scripts/compile_and_run.sh +0 -219
  81. package/Scripts/compile_and_run_adhoc.sh +0 -4
  82. package/Scripts/docs-list.mjs +0 -119
  83. package/Scripts/make_appcast.sh +0 -58
  84. package/Scripts/package_app.sh +0 -409
  85. package/Scripts/release-lib.sh +0 -214
  86. package/Scripts/release.sh +0 -76
  87. package/Scripts/setup-all.sh +0 -387
  88. package/Scripts/setup-ios.sh +0 -404
  89. package/Scripts/setup-react-native.sh +0 -523
  90. package/Scripts/sign-and-notarize.sh +0 -122
  91. package/Scripts/test_live_update.sh +0 -38
  92. package/Scripts/validate_changelog.sh +0 -23
  93. package/Scripts/verify_appcast.sh +0 -92
  94. package/Sources/Runic/About.swift +0 -93
  95. package/Sources/Runic/AppNotifications.swift +0 -117
  96. package/Sources/Runic/Controllers/StatusItemController+Actions.swift +0 -670
  97. package/Sources/Runic/Controllers/StatusItemController+Animation.swift +0 -519
  98. package/Sources/Runic/Controllers/StatusItemController+ChartSubmenus.swift +0 -824
  99. package/Sources/Runic/Controllers/StatusItemController+CustomProviders.swift +0 -90
  100. package/Sources/Runic/Controllers/StatusItemController+Menu.swift +0 -1412
  101. package/Sources/Runic/Controllers/StatusItemController+MenuCards.swift +0 -339
  102. package/Sources/Runic/Controllers/StatusItemController+MenuHelpers.swift +0 -423
  103. package/Sources/Runic/Controllers/StatusItemController.swift +0 -360
  104. package/Sources/Runic/Core/BudgetNotificationManager.swift +0 -81
  105. package/Sources/Runic/Core/Login/ClaudeLoginRunner.swift +0 -103
  106. package/Sources/Runic/Core/Login/CodexLoginRunner.swift +0 -154
  107. package/Sources/Runic/Core/Login/CursorLoginRunner.swift +0 -206
  108. package/Sources/Runic/Core/Login/GeminiLoginRunner.swift +0 -92
  109. package/Sources/Runic/Core/Rendering/IconRenderer.swift +0 -1222
  110. package/Sources/Runic/Core/Rendering/IconView.swift +0 -122
  111. package/Sources/Runic/Core/Rendering/ProviderBrandIcon.swift +0 -71
  112. package/Sources/Runic/Core/RunicAnimation.swift +0 -53
  113. package/Sources/Runic/Core/RunicColors.swift +0 -73
  114. package/Sources/Runic/Core/RunicCornerRadius.swift +0 -15
  115. package/Sources/Runic/Core/RunicSpacing.swift +0 -68
  116. package/Sources/Runic/Core/RunicTypography.swift +0 -206
  117. package/Sources/Runic/Core/Stores/AuggieTokenStore.swift +0 -117
  118. package/Sources/Runic/Core/Stores/AzureOpenAITokenStore.swift +0 -117
  119. package/Sources/Runic/Core/Stores/CerebrasTokenStore.swift +0 -117
  120. package/Sources/Runic/Core/Stores/CohereTokenStore.swift +0 -117
  121. package/Sources/Runic/Core/Stores/CopilotTokenStore.swift +0 -117
  122. package/Sources/Runic/Core/Stores/CustomProviderStore.swift +0 -158
  123. package/Sources/Runic/Core/Stores/DeepSeekTokenStore.swift +0 -117
  124. package/Sources/Runic/Core/Stores/FireworksTokenStore.swift +0 -117
  125. package/Sources/Runic/Core/Stores/GroqTokenStore.swift +0 -117
  126. package/Sources/Runic/Core/Stores/KimiTokenStore.swift +0 -117
  127. package/Sources/Runic/Core/Stores/MiniMaxCookieHeaderStore.swift +0 -117
  128. package/Sources/Runic/Core/Stores/MiniMaxGroupIDStore.swift +0 -117
  129. package/Sources/Runic/Core/Stores/MiniMaxTokenStore.swift +0 -117
  130. package/Sources/Runic/Core/Stores/MistralTokenStore.swift +0 -117
  131. package/Sources/Runic/Core/Stores/OpenRouterTokenStore.swift +0 -117
  132. package/Sources/Runic/Core/Stores/PerplexityTokenStore.swift +0 -117
  133. package/Sources/Runic/Core/Stores/ProviderToggleStore.swift +0 -30
  134. package/Sources/Runic/Core/Stores/QwenTokenStore.swift +0 -117
  135. package/Sources/Runic/Core/Stores/SambaNovaTokenStore.swift +0 -117
  136. package/Sources/Runic/Core/Stores/SettingsStore.swift +0 -1749
  137. package/Sources/Runic/Core/Stores/TogetherTokenStore.swift +0 -117
  138. package/Sources/Runic/Core/Stores/UsageStore+Accessors.swift +0 -33
  139. package/Sources/Runic/Core/Stores/UsageStore+Status.swift +0 -189
  140. package/Sources/Runic/Core/Stores/UsageStore+TokenCost.swift +0 -33
  141. package/Sources/Runic/Core/Stores/UsageStore+WidgetSnapshot.swift +0 -67
  142. package/Sources/Runic/Core/Stores/UsageStore.swift +0 -3631
  143. package/Sources/Runic/Core/Stores/XAITokenStore.swift +0 -117
  144. package/Sources/Runic/Core/Stores/ZaiTokenStore.swift +0 -117
  145. package/Sources/Runic/Core/UsageExporter.swift +0 -197
  146. package/Sources/Runic/Date+RelativeDescription.swift +0 -21
  147. package/Sources/Runic/HiddenWindowView.swift +0 -32
  148. package/Sources/Runic/InstallOrigin.swift +0 -9
  149. package/Sources/Runic/KeyboardShortcuts+Names.swift +0 -6
  150. package/Sources/Runic/MouseLocationReader.swift +0 -65
  151. package/Sources/Runic/Notifications+Runic.swift +0 -6
  152. package/Sources/Runic/OpenAICreditsPurchaseWindowController.swift +0 -503
  153. package/Sources/Runic/ProviderRegistry.swift +0 -100
  154. package/Sources/Runic/ProviderSwitcherButtons.swift +0 -267
  155. package/Sources/Runic/Providers/Antigravity/AntigravityLoginFlow.swift +0 -11
  156. package/Sources/Runic/Providers/Antigravity/AntigravityProviderImplementation.swift +0 -14
  157. package/Sources/Runic/Providers/Auggie/AuggieProviderImplementation.swift +0 -24
  158. package/Sources/Runic/Providers/Azure/AzureProviderImplementation.swift +0 -52
  159. package/Sources/Runic/Providers/Bedrock/BedrockProviderImplementation.swift +0 -42
  160. package/Sources/Runic/Providers/Cerebras/CerebrasProviderImplementation.swift +0 -24
  161. package/Sources/Runic/Providers/Claude/ClaudeLoginFlow.swift +0 -26
  162. package/Sources/Runic/Providers/Claude/ClaudeProviderImplementation.swift +0 -14
  163. package/Sources/Runic/Providers/Codex/CodexLoginFlow.swift +0 -18
  164. package/Sources/Runic/Providers/Codex/CodexProviderImplementation.swift +0 -15
  165. package/Sources/Runic/Providers/Cohere/CohereProviderImplementation.swift +0 -24
  166. package/Sources/Runic/Providers/Copilot/CopilotLoginFlow.swift +0 -193
  167. package/Sources/Runic/Providers/Copilot/CopilotProviderImplementation.swift +0 -110
  168. package/Sources/Runic/Providers/Cursor/CursorLoginFlow.swift +0 -28
  169. package/Sources/Runic/Providers/Cursor/CursorProviderImplementation.swift +0 -15
  170. package/Sources/Runic/Providers/DeepSeek/DeepSeekProviderImplementation.swift +0 -24
  171. package/Sources/Runic/Providers/Factory/FactoryLoginFlow.swift +0 -12
  172. package/Sources/Runic/Providers/Factory/FactoryProviderImplementation.swift +0 -15
  173. package/Sources/Runic/Providers/Fireworks/FireworksProviderImplementation.swift +0 -24
  174. package/Sources/Runic/Providers/Gemini/GeminiLoginFlow.swift +0 -20
  175. package/Sources/Runic/Providers/Gemini/GeminiProviderImplementation.swift +0 -15
  176. package/Sources/Runic/Providers/Groq/GroqProviderImplementation.swift +0 -24
  177. package/Sources/Runic/Providers/Kimi/KimiProviderImplementation.swift +0 -24
  178. package/Sources/Runic/Providers/MiniMax/MiniMaxProviderImplementation.swift +0 -32
  179. package/Sources/Runic/Providers/Mistral/MistralProviderImplementation.swift +0 -24
  180. package/Sources/Runic/Providers/OpenRouter/OpenRouterProviderImplementation.swift +0 -24
  181. package/Sources/Runic/Providers/Perplexity/PerplexityProviderImplementation.swift +0 -24
  182. package/Sources/Runic/Providers/SambaNova/SambaNovaProviderImplementation.swift +0 -24
  183. package/Sources/Runic/Providers/Shared/ProviderCatalog.swift +0 -15
  184. package/Sources/Runic/Providers/Shared/ProviderImplementation.swift +0 -51
  185. package/Sources/Runic/Providers/Shared/ProviderImplementationRegistry.swift +0 -66
  186. package/Sources/Runic/Providers/Shared/ProviderLoginFlow.swift +0 -12
  187. package/Sources/Runic/Providers/Shared/ProviderSettingsDescriptors.swift +0 -99
  188. package/Sources/Runic/Providers/Shared/SystemSettingsLinks.swift +0 -18
  189. package/Sources/Runic/Providers/Together/TogetherProviderImplementation.swift +0 -24
  190. package/Sources/Runic/Providers/XAI/XAIProviderImplementation.swift +0 -24
  191. package/Sources/Runic/Providers/Zai/ZaiProviderImplementation.swift +0 -24
  192. package/Sources/Runic/Resources/Fonts/Caveat-Bold.ttf +0 -0
  193. package/Sources/Runic/Resources/Fonts/Caveat-Regular.ttf +0 -0
  194. package/Sources/Runic/Resources/Fonts/FiraCode-Bold.ttf +0 -0
  195. package/Sources/Runic/Resources/Fonts/FiraCode-Light.ttf +0 -0
  196. package/Sources/Runic/Resources/Fonts/FiraCode-Medium.ttf +0 -0
  197. package/Sources/Runic/Resources/Fonts/FiraCode-Regular.ttf +0 -0
  198. package/Sources/Runic/Resources/Fonts/FiraCode-SemiBold.ttf +0 -0
  199. package/Sources/Runic/Resources/Fonts/IBMPlexMono-Bold.ttf +0 -0
  200. package/Sources/Runic/Resources/Fonts/IBMPlexMono-Medium.ttf +0 -0
  201. package/Sources/Runic/Resources/Fonts/IBMPlexMono-Regular.ttf +0 -0
  202. package/Sources/Runic/Resources/Fonts/IBMPlexMono-SemiBold.ttf +0 -0
  203. package/Sources/Runic/Resources/Fonts/Inconsolata-Bold.ttf +0 -0
  204. package/Sources/Runic/Resources/Fonts/Inconsolata-Medium.ttf +0 -0
  205. package/Sources/Runic/Resources/Fonts/Inconsolata-Regular.ttf +0 -0
  206. package/Sources/Runic/Resources/Fonts/Inconsolata-SemiBold.ttf +0 -0
  207. package/Sources/Runic/Resources/Fonts/JetBrainsMono-Bold.ttf +0 -0
  208. package/Sources/Runic/Resources/Fonts/JetBrainsMono-Medium.ttf +0 -0
  209. package/Sources/Runic/Resources/Fonts/JetBrainsMono-Regular.ttf +0 -0
  210. package/Sources/Runic/Resources/Fonts/JetBrainsMono-SemiBold.ttf +0 -0
  211. package/Sources/Runic/Resources/Fonts/SpaceMono-Bold.ttf +0 -0
  212. package/Sources/Runic/Resources/Fonts/SpaceMono-Regular.ttf +0 -0
  213. package/Sources/Runic/Resources/ProviderIcon-antigravity.svg +0 -2
  214. package/Sources/Runic/Resources/ProviderIcon-auggie.svg +0 -3
  215. package/Sources/Runic/Resources/ProviderIcon-azure.svg +0 -5
  216. package/Sources/Runic/Resources/ProviderIcon-bedrock.svg +0 -7
  217. package/Sources/Runic/Resources/ProviderIcon-cerebras.svg +0 -3
  218. package/Sources/Runic/Resources/ProviderIcon-claude.svg +0 -1
  219. package/Sources/Runic/Resources/ProviderIcon-codex.svg +0 -1
  220. package/Sources/Runic/Resources/ProviderIcon-cohere.svg +0 -3
  221. package/Sources/Runic/Resources/ProviderIcon-copilot.svg +0 -1
  222. package/Sources/Runic/Resources/ProviderIcon-cursor.svg +0 -3
  223. package/Sources/Runic/Resources/ProviderIcon-deepseek.svg +0 -4
  224. package/Sources/Runic/Resources/ProviderIcon-factory.svg +0 -3
  225. package/Sources/Runic/Resources/ProviderIcon-fireworks.svg +0 -3
  226. package/Sources/Runic/Resources/ProviderIcon-gemini.svg +0 -1
  227. package/Sources/Runic/Resources/ProviderIcon-groq.svg +0 -1
  228. package/Sources/Runic/Resources/ProviderIcon-kimi.svg +0 -4
  229. package/Sources/Runic/Resources/ProviderIcon-minimax.svg +0 -1
  230. package/Sources/Runic/Resources/ProviderIcon-mistral.svg +0 -5
  231. package/Sources/Runic/Resources/ProviderIcon-openrouter.svg +0 -7
  232. package/Sources/Runic/Resources/ProviderIcon-perplexity.svg +0 -4
  233. package/Sources/Runic/Resources/ProviderIcon-qwen.svg +0 -9
  234. package/Sources/Runic/Resources/ProviderIcon-sambanova.svg +0 -4
  235. package/Sources/Runic/Resources/ProviderIcon-together.svg +0 -5
  236. package/Sources/Runic/Resources/ProviderIcon-vertexai.svg +0 -17
  237. package/Sources/Runic/Resources/ProviderIcon-xai.svg +0 -3
  238. package/Sources/Runic/Resources/ProviderIcon-zai.svg +0 -5
  239. package/Sources/Runic/Resources/RunicMenubarIcon.svg +0 -7
  240. package/Sources/Runic/Resources/provider-context-windows.json +0 -20
  241. package/Sources/Runic/RunicApp.swift +0 -367
  242. package/Sources/Runic/SessionQuotaNotifications.swift +0 -58
  243. package/Sources/Runic/UsagePaceText.swift +0 -52
  244. package/Sources/Runic/UsageProgressBar.swift +0 -228
  245. package/Sources/Runic/Utilities/DisplayLink.swift +0 -96
  246. package/Sources/Runic/Utilities/LoadingPattern.swift +0 -62
  247. package/Sources/Runic/Utilities/PerformanceConstants.swift +0 -85
  248. package/Sources/Runic/Views/Menu/AlertsMenuView.swift +0 -254
  249. package/Sources/Runic/Views/Menu/ChartPanelStyle.swift +0 -22
  250. package/Sources/Runic/Views/Menu/CostComparativeChartMenuView.swift +0 -275
  251. package/Sources/Runic/Views/Menu/CostHistoryChartMenuView.swift +0 -377
  252. package/Sources/Runic/Views/Menu/CreditsHistoryChartMenuView.swift +0 -312
  253. package/Sources/Runic/Views/Menu/EfficiencyMetricsMenuView.swift +0 -311
  254. package/Sources/Runic/Views/Menu/HeroStatCardsMenuView.swift +0 -231
  255. package/Sources/Runic/Views/Menu/HourlyActivityChartMenuView.swift +0 -228
  256. package/Sources/Runic/Views/Menu/InlineUsageChartView.swift +0 -157
  257. package/Sources/Runic/Views/Menu/MenuCardEntranceModifier.swift +0 -63
  258. package/Sources/Runic/Views/Menu/MenuCardSidebarView.swift +0 -248
  259. package/Sources/Runic/Views/Menu/MenuCardSkeletonView.swift +0 -104
  260. package/Sources/Runic/Views/Menu/MenuCardView.swift +0 -1889
  261. package/Sources/Runic/Views/Menu/MenuContent.swift +0 -153
  262. package/Sources/Runic/Views/Menu/MenuDescriptor.swift +0 -371
  263. package/Sources/Runic/Views/Menu/MenuHighlightStyle.swift +0 -35
  264. package/Sources/Runic/Views/Menu/ModelBreakdownMenuView.swift +0 -241
  265. package/Sources/Runic/Views/Menu/OverviewMenuView.swift +0 -281
  266. package/Sources/Runic/Views/Menu/ProjectBreakdownMenuView.swift +0 -214
  267. package/Sources/Runic/Views/Menu/ProjectBudgetMenuView.swift +0 -220
  268. package/Sources/Runic/Views/Menu/ProviderTabBarView.swift +0 -86
  269. package/Sources/Runic/Views/Menu/SubscriptionUtilizationChartMenuView.swift +0 -214
  270. package/Sources/Runic/Views/Menu/UsageBreakdownChartMenuView.swift +0 -398
  271. package/Sources/Runic/Views/Menu/UsageHeatmapMenuView.swift +0 -231
  272. package/Sources/Runic/Views/Menu/UsageTimelineChartMenuView.swift +0 -369
  273. package/Sources/Runic/Views/Menu/UsageWindowComparisonChartMenuView.swift +0 -191
  274. package/Sources/Runic/Views/Menu/WeeklyActivityChartMenuView.swift +0 -132
  275. package/Sources/Runic/Views/Performance/PerformanceDashboardView.swift +0 -621
  276. package/Sources/Runic/Views/Preferences/LiquidComponents.swift +0 -306
  277. package/Sources/Runic/Views/Preferences/PreferencesAboutPane.swift +0 -271
  278. package/Sources/Runic/Views/Preferences/PreferencesAdvancedPane.swift +0 -268
  279. package/Sources/Runic/Views/Preferences/PreferencesAlertsPane.swift +0 -418
  280. package/Sources/Runic/Views/Preferences/PreferencesAnalyticsPane.swift +0 -637
  281. package/Sources/Runic/Views/Preferences/PreferencesBudgetsPane.swift +0 -344
  282. package/Sources/Runic/Views/Preferences/PreferencesComponents.swift +0 -230
  283. package/Sources/Runic/Views/Preferences/PreferencesCustomProvidersPane.swift +0 -321
  284. package/Sources/Runic/Views/Preferences/PreferencesDebugPane.swift +0 -469
  285. package/Sources/Runic/Views/Preferences/PreferencesGeneralPane.swift +0 -250
  286. package/Sources/Runic/Views/Preferences/PreferencesHelpPane.swift +0 -50
  287. package/Sources/Runic/Views/Preferences/PreferencesIntegrationsPane.swift +0 -572
  288. package/Sources/Runic/Views/Preferences/PreferencesPerformancePane.swift +0 -291
  289. package/Sources/Runic/Views/Preferences/PreferencesProvidersPane.swift +0 -3480
  290. package/Sources/Runic/Views/Preferences/PreferencesSelection.swift +0 -29
  291. package/Sources/Runic/Views/Preferences/PreferencesSyncPane.swift +0 -61
  292. package/Sources/Runic/Views/Preferences/PreferencesView.swift +0 -213
  293. package/Sources/Runic/Views/Rating/QualityRatingView.swift +0 -238
  294. package/Sources/Runic/Views/Team/TeamDashboardView.swift +0 -376
  295. package/Sources/Runic/Views/Team/TeamInviteSheet.swift +0 -175
  296. package/Sources/Runic/Views/Team/TeamManagementView.swift +0 -762
  297. package/Sources/Runic/Views/Team/TeamMemberRow.swift +0 -181
  298. package/Sources/RunicCLI/CLIEntry.swift +0 -983
  299. package/Sources/RunicCLI/CLIRenderer.swift +0 -87
  300. package/Sources/RunicCLI/Commands/EnhancedUsageCommand.swift +0 -588
  301. package/Sources/RunicCLI/Commands/ModelsCommand.swift +0 -363
  302. package/Sources/RunicCLI/Commands/ProjectsCommand.swift +0 -453
  303. package/Sources/RunicCLI/Commands/ResetCommand.swift +0 -430
  304. package/Sources/RunicCLI/Commands/UsageLedgerSourceFactory.swift +0 -167
  305. package/Sources/RunicClaudeWatchdog/main.swift +0 -122
  306. package/Sources/RunicClaudeWebProbe/main.swift +0 -62
  307. package/Sources/RunicCore/AlertRuleStore.swift +0 -187
  308. package/Sources/RunicCore/BrowserCookieImportOrder.swift +0 -25
  309. package/Sources/RunicCore/CopilotUsageModels.swift +0 -84
  310. package/Sources/RunicCore/CostUsageFetcher.swift +0 -119
  311. package/Sources/RunicCore/CostUsageModels.swift +0 -479
  312. package/Sources/RunicCore/CreditsModels.swift +0 -50
  313. package/Sources/RunicCore/CustomProviders/CustomProviderModels.swift +0 -268
  314. package/Sources/RunicCore/CustomProviders/GenericProviderFetcher.swift +0 -631
  315. package/Sources/RunicCore/CustomProviders/ProviderTemplates.swift +0 -444
  316. package/Sources/RunicCore/Host/PTY/TTYCommandRunner.swift +0 -679
  317. package/Sources/RunicCore/Host/Process/SubprocessRunner.swift +0 -135
  318. package/Sources/RunicCore/Integrations/GitHubIntegration.swift +0 -173
  319. package/Sources/RunicCore/Logging/JSONStderrLogHandler.swift +0 -79
  320. package/Sources/RunicCore/Logging/OSLogLogHandler.swift +0 -86
  321. package/Sources/RunicCore/Logging/RunicLog.swift +0 -123
  322. package/Sources/RunicCore/Models/EnhancedUsageModels.swift +0 -370
  323. package/Sources/RunicCore/OpenAIDashboardModels.swift +0 -210
  324. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardBrowserCookieImporter.swift +0 -676
  325. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardFetcher.swift +0 -492
  326. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardNavigationDelegate.swift +0 -51
  327. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardParser.swift +0 -483
  328. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardScrapeScript.swift +0 -558
  329. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardWebViewCache.swift +0 -204
  330. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardWebsiteDataStore.swift +0 -78
  331. package/Sources/RunicCore/PathEnvironment.swift +0 -482
  332. package/Sources/RunicCore/Performance/PerformanceModels.swift +0 -371
  333. package/Sources/RunicCore/Performance/PerformanceStorageImpl.swift +0 -426
  334. package/Sources/RunicCore/Policy/UsagePolicyEngine.swift +0 -178
  335. package/Sources/RunicCore/ProjectBudgetStore.swift +0 -102
  336. package/Sources/RunicCore/ProviderCostSnapshot.swift +0 -29
  337. package/Sources/RunicCore/Providers/Antigravity/AntigravityProviderDescriptor.swift +0 -68
  338. package/Sources/RunicCore/Providers/Antigravity/AntigravityStatusProbe.swift +0 -685
  339. package/Sources/RunicCore/Providers/Auggie/AuggieProviderDescriptor.swift +0 -83
  340. package/Sources/RunicCore/Providers/Auggie/AuggieUsageFetcher.swift +0 -142
  341. package/Sources/RunicCore/Providers/Azure/AzureProviderDescriptor.swift +0 -141
  342. package/Sources/RunicCore/Providers/Azure/AzureUsageFetcher.swift +0 -188
  343. package/Sources/RunicCore/Providers/Bedrock/BedrockProviderDescriptor.swift +0 -126
  344. package/Sources/RunicCore/Providers/Bedrock/BedrockUsageFetcher.swift +0 -164
  345. package/Sources/RunicCore/Providers/Cerebras/CerebrasProviderDescriptor.swift +0 -84
  346. package/Sources/RunicCore/Providers/Cerebras/CerebrasUsageFetcher.swift +0 -75
  347. package/Sources/RunicCore/Providers/Claude/ClaudeCLISession.swift +0 -332
  348. package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthCredentials.swift +0 -180
  349. package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthUsageFetcher.swift +0 -137
  350. package/Sources/RunicCore/Providers/Claude/ClaudeProviderDescriptor.swift +0 -209
  351. package/Sources/RunicCore/Providers/Claude/ClaudeStatusProbe.swift +0 -654
  352. package/Sources/RunicCore/Providers/Claude/ClaudeUsageDataSource.swift +0 -30
  353. package/Sources/RunicCore/Providers/Claude/ClaudeUsageFetcher.swift +0 -480
  354. package/Sources/RunicCore/Providers/Claude/ClaudeWeb/ClaudeWebAPIFetcher.swift +0 -780
  355. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthCredentials.swift +0 -147
  356. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthUsageFetcher.swift +0 -280
  357. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexTokenRefresher.swift +0 -100
  358. package/Sources/RunicCore/Providers/Codex/CodexProviderDescriptor.swift +0 -245
  359. package/Sources/RunicCore/Providers/Codex/CodexStatusProbe.swift +0 -125
  360. package/Sources/RunicCore/Providers/Codex/CodexUsageDataSource.swift +0 -26
  361. package/Sources/RunicCore/Providers/Codex/CodexWebDashboardStrategy.swift +0 -183
  362. package/Sources/RunicCore/Providers/Cohere/CohereProviderDescriptor.swift +0 -83
  363. package/Sources/RunicCore/Providers/Cohere/CohereUsageFetcher.swift +0 -85
  364. package/Sources/RunicCore/Providers/Copilot/CopilotDeviceFlow.swift +0 -123
  365. package/Sources/RunicCore/Providers/Copilot/CopilotGitHubCLITokenReader.swift +0 -117
  366. package/Sources/RunicCore/Providers/Copilot/CopilotProviderDescriptor.swift +0 -100
  367. package/Sources/RunicCore/Providers/Copilot/CopilotUsageFetcher.swift +0 -293
  368. package/Sources/RunicCore/Providers/Copilot/CopilotVSCodeTokenReader.swift +0 -385
  369. package/Sources/RunicCore/Providers/Cursor/CursorProviderDescriptor.swift +0 -67
  370. package/Sources/RunicCore/Providers/Cursor/CursorStatusProbe.swift +0 -595
  371. package/Sources/RunicCore/Providers/DeepSeek/DeepSeekProviderDescriptor.swift +0 -85
  372. package/Sources/RunicCore/Providers/DeepSeek/DeepSeekUsageFetcher.swift +0 -108
  373. package/Sources/RunicCore/Providers/Factory/FactoryLocalStorageImporter.swift +0 -398
  374. package/Sources/RunicCore/Providers/Factory/FactoryProviderDescriptor.swift +0 -67
  375. package/Sources/RunicCore/Providers/Factory/FactoryStatusProbe.swift +0 -1276
  376. package/Sources/RunicCore/Providers/Fireworks/FireworksProviderDescriptor.swift +0 -84
  377. package/Sources/RunicCore/Providers/Fireworks/FireworksUsageFetcher.swift +0 -75
  378. package/Sources/RunicCore/Providers/Gemini/GeminiProviderDescriptor.swift +0 -67
  379. package/Sources/RunicCore/Providers/Gemini/GeminiStatusProbe.swift +0 -839
  380. package/Sources/RunicCore/Providers/Groq/GroqProviderDescriptor.swift +0 -83
  381. package/Sources/RunicCore/Providers/Groq/GroqUsageFetcher.swift +0 -71
  382. package/Sources/RunicCore/Providers/Kimi/KimiProviderDescriptor.swift +0 -83
  383. package/Sources/RunicCore/Providers/Kimi/KimiUsageFetcher.swift +0 -77
  384. package/Sources/RunicCore/Providers/MiniMax/MiniMaxProviderDescriptor.swift +0 -97
  385. package/Sources/RunicCore/Providers/MiniMax/MiniMaxSettingsReader.swift +0 -54
  386. package/Sources/RunicCore/Providers/MiniMax/MiniMaxUsageFetcher.swift +0 -168
  387. package/Sources/RunicCore/Providers/MiniMax/MiniMaxWebUsageFetcher.swift +0 -911
  388. package/Sources/RunicCore/Providers/Mistral/MistralProviderDescriptor.swift +0 -84
  389. package/Sources/RunicCore/Providers/Mistral/MistralUsageFetcher.swift +0 -75
  390. package/Sources/RunicCore/Providers/OpenRouter/OpenRouterProviderDescriptor.swift +0 -87
  391. package/Sources/RunicCore/Providers/OpenRouter/OpenRouterUsageFetcher.swift +0 -216
  392. package/Sources/RunicCore/Providers/Perplexity/PerplexityProviderDescriptor.swift +0 -84
  393. package/Sources/RunicCore/Providers/Perplexity/PerplexityUsageFetcher.swift +0 -75
  394. package/Sources/RunicCore/Providers/ProviderBranding.swift +0 -25
  395. package/Sources/RunicCore/Providers/ProviderCLIConfig.swift +0 -17
  396. package/Sources/RunicCore/Providers/ProviderDescriptor.swift +0 -129
  397. package/Sources/RunicCore/Providers/ProviderFetchPlan.swift +0 -263
  398. package/Sources/RunicCore/Providers/ProviderSettingsSnapshot.swift +0 -98
  399. package/Sources/RunicCore/Providers/ProviderTokenResolver.swift +0 -501
  400. package/Sources/RunicCore/Providers/ProviderVersionDetector.swift +0 -68
  401. package/Sources/RunicCore/Providers/Providers.swift +0 -184
  402. package/Sources/RunicCore/Providers/Qwen/QwenProviderDescriptor.swift +0 -86
  403. package/Sources/RunicCore/Providers/Qwen/QwenSettingsReader.swift +0 -30
  404. package/Sources/RunicCore/Providers/Qwen/QwenUsageStats.swift +0 -328
  405. package/Sources/RunicCore/Providers/SambaNova/SambaNovaProviderDescriptor.swift +0 -84
  406. package/Sources/RunicCore/Providers/SambaNova/SambaNovaUsageFetcher.swift +0 -75
  407. package/Sources/RunicCore/Providers/Together/TogetherProviderDescriptor.swift +0 -83
  408. package/Sources/RunicCore/Providers/Together/TogetherUsageFetcher.swift +0 -75
  409. package/Sources/RunicCore/Providers/VertexAI/VertexAIProviderDescriptor.swift +0 -123
  410. package/Sources/RunicCore/Providers/VertexAI/VertexAISettingsReader.swift +0 -48
  411. package/Sources/RunicCore/Providers/VertexAI/VertexAIUsageFetcher.swift +0 -144
  412. package/Sources/RunicCore/Providers/XAI/XAIProviderDescriptor.swift +0 -83
  413. package/Sources/RunicCore/Providers/XAI/XAIUsageFetcher.swift +0 -75
  414. package/Sources/RunicCore/Providers/Zai/ZaiProviderDescriptor.swift +0 -74
  415. package/Sources/RunicCore/Providers/Zai/ZaiSettingsReader.swift +0 -41
  416. package/Sources/RunicCore/Providers/Zai/ZaiUsageStats.swift +0 -745
  417. package/Sources/RunicCore/Sync/BackgroundSyncManager.swift +0 -384
  418. package/Sources/RunicCore/Sync/SyncConflictResolver.swift +0 -307
  419. package/Sources/RunicCore/Sync/SyncProtocol.swift +0 -287
  420. package/Sources/RunicCore/Sync/SyncRecord.swift +0 -402
  421. package/Sources/RunicCore/Sync/SyncUsageExample.swift +0 -288
  422. package/Sources/RunicCore/Sync/TeamSyncRecords.swift +0 -768
  423. package/Sources/RunicCore/Sync/iCloudSyncEngine.swift +0 -338
  424. package/Sources/RunicCore/Team/TeamModels.swift +0 -584
  425. package/Sources/RunicCore/Team/TeamShowbackExporter.swift +0 -495
  426. package/Sources/RunicCore/Team/TeamStore.swift +0 -809
  427. package/Sources/RunicCore/TextParsing.swift +0 -55
  428. package/Sources/RunicCore/UsageFetcher.swift +0 -694
  429. package/Sources/RunicCore/UsageFormatter.swift +0 -410
  430. package/Sources/RunicCore/UsageLedger/ClaudeUsageLogSource.swift +0 -441
  431. package/Sources/RunicCore/UsageLedger/CodexUsageLogSource.swift +0 -502
  432. package/Sources/RunicCore/UsageLedger/LedgerCache.swift +0 -161
  433. package/Sources/RunicCore/UsageLedger/OTelGenAILedgerAdapter.swift +0 -550
  434. package/Sources/RunicCore/UsageLedger/UsageLedger.swift +0 -29
  435. package/Sources/RunicCore/UsageLedger/UsageLedgerAggregator.swift +0 -675
  436. package/Sources/RunicCore/UsageLedger/UsageLedgerInsightsAdvisor.swift +0 -209
  437. package/Sources/RunicCore/UsageLedger/UsageLedgerModels.swift +0 -417
  438. package/Sources/RunicCore/UsageLedger/UsageLedgerProjectIdentity.swift +0 -284
  439. package/Sources/RunicCore/UsagePace.swift +0 -81
  440. package/Sources/RunicCore/Vendored/CostUsage/CostUsageCache.swift +0 -73
  441. package/Sources/RunicCore/Vendored/CostUsage/CostUsageJsonl.swift +0 -74
  442. package/Sources/RunicCore/Vendored/CostUsage/CostUsagePricing.swift +0 -208
  443. package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner+Claude.swift +0 -455
  444. package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner+Timestamp.swift +0 -132
  445. package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner.swift +0 -589
  446. package/Sources/RunicCore/WidgetSnapshot.swift +0 -183
  447. package/Sources/RunicMacroSupport/ProviderRegistrationMacros.swift +0 -14
  448. package/Sources/RunicMacros/ProviderRegistrationMacros.swift +0 -216
  449. package/Sources/RunicWidget/RunicWidgetBundle.swift +0 -79
  450. package/Sources/RunicWidget/RunicWidgetProvider.swift +0 -283
  451. package/Sources/RunicWidget/RunicWidgetViews.swift +0 -680
  452. package/Tests/RunicTests/AntigravityStatusProbeTests.swift +0 -50
  453. package/Tests/RunicTests/AppDelegateTests.swift +0 -48
  454. package/Tests/RunicTests/BrowserCookieOrderLabelTests.swift +0 -21
  455. package/Tests/RunicTests/CLIArgumentParsingTests.swift +0 -69
  456. package/Tests/RunicTests/CLICostTests.swift +0 -64
  457. package/Tests/RunicTests/CLIProviderSelectionTests.swift +0 -21
  458. package/Tests/RunicTests/CLISnapshotTests.swift +0 -71
  459. package/Tests/RunicTests/CLIWebFallbackTests.swift +0 -57
  460. package/Tests/RunicTests/ClaudeOAuthTests.swift +0 -163
  461. package/Tests/RunicTests/ClaudeResilienceTests.swift +0 -29
  462. package/Tests/RunicTests/ClaudeUsageTests.swift +0 -369
  463. package/Tests/RunicTests/CodexOAuthTests.swift +0 -121
  464. package/Tests/RunicTests/CodexUsageLogSourceTests.swift +0 -80
  465. package/Tests/RunicTests/CopilotTokenResolverTests.swift +0 -74
  466. package/Tests/RunicTests/CopilotVSCodeTokenReaderTests.swift +0 -74
  467. package/Tests/RunicTests/CostUsageDecodingTests.swift +0 -392
  468. package/Tests/RunicTests/CostUsagePricingTests.swift +0 -48
  469. package/Tests/RunicTests/CostUsageScannerTests.swift +0 -698
  470. package/Tests/RunicTests/CursorStatusProbeTests.swift +0 -322
  471. package/Tests/RunicTests/FactoryStatusProbeTests.swift +0 -67
  472. package/Tests/RunicTests/GeminiAPITestHelpers.swift +0 -94
  473. package/Tests/RunicTests/GeminiLoginAlertTests.swift +0 -27
  474. package/Tests/RunicTests/GeminiStatusProbeAPITests.swift +0 -283
  475. package/Tests/RunicTests/GeminiStatusProbePlanTests.swift +0 -279
  476. package/Tests/RunicTests/GeminiStatusProbeTests.swift +0 -232
  477. package/Tests/RunicTests/GeminiTestEnvironment.swift +0 -87
  478. package/Tests/RunicTests/GoogleWorkspaceStatusTests.swift +0 -72
  479. package/Tests/RunicTests/InstallOriginTests.swift +0 -17
  480. package/Tests/RunicTests/KeyboardShortcutsBundleTests.swift +0 -9
  481. package/Tests/RunicTests/LiveAccountTests.swift +0 -24
  482. package/Tests/RunicTests/LoadingPatternTests.swift +0 -34
  483. package/Tests/RunicTests/MenuCardModelTests.swift +0 -544
  484. package/Tests/RunicTests/MiniMaxCookieHeaderStoreTestSupport.swift +0 -11
  485. package/Tests/RunicTests/MiniMaxGroupIDStoreTestSupport.swift +0 -11
  486. package/Tests/RunicTests/MiniMaxParsingTests.swift +0 -67
  487. package/Tests/RunicTests/MiniMaxTokenStoreTestSupport.swift +0 -11
  488. package/Tests/RunicTests/OTelGenAILedgerAdapterTests.swift +0 -110
  489. package/Tests/RunicTests/OpenAIDashboardBrowserCookieImporterTests.swift +0 -16
  490. package/Tests/RunicTests/OpenAIDashboardFetcherCreditsWaitTests.swift +0 -74
  491. package/Tests/RunicTests/OpenAIDashboardOffscreenHostTests.swift +0 -26
  492. package/Tests/RunicTests/OpenAIDashboardParserTests.swift +0 -133
  493. package/Tests/RunicTests/OpenAIWebAccountSwitchTests.swift +0 -64
  494. package/Tests/RunicTests/OpenRouterTokenStoreTestSupport.swift +0 -131
  495. package/Tests/RunicTests/PathBuilderTests.swift +0 -236
  496. package/Tests/RunicTests/ProviderFetchPipelineTests.swift +0 -159
  497. package/Tests/RunicTests/ProviderIconResourcesTests.swift +0 -37
  498. package/Tests/RunicTests/ProviderMetadataStatusLinkTests.swift +0 -15
  499. package/Tests/RunicTests/ProviderRegistryTests.swift +0 -29
  500. package/Tests/RunicTests/ProviderSettingsDescriptorTests.swift +0 -236
  501. package/Tests/RunicTests/ProviderToggleStoreTests.swift +0 -50
  502. package/Tests/RunicTests/RunicTests.swift +0 -119
  503. package/Tests/RunicTests/SessionQuotaNotificationLogicTests.swift +0 -35
  504. package/Tests/RunicTests/SettingsStoreTests.swift +0 -265
  505. package/Tests/RunicTests/StatusItemAnimationTests.swift +0 -54
  506. package/Tests/RunicTests/StatusMenuTests.swift +0 -475
  507. package/Tests/RunicTests/StatusProbeTests.swift +0 -376
  508. package/Tests/RunicTests/SubprocessRunnerTests.swift +0 -18
  509. package/Tests/RunicTests/SubscriptionDetectionTests.swift +0 -64
  510. package/Tests/RunicTests/TTYCommandRunnerTests.swift +0 -147
  511. package/Tests/RunicTests/TTYIntegrationTests.swift +0 -41
  512. package/Tests/RunicTests/TeamShowbackExporterTests.swift +0 -157
  513. package/Tests/RunicTests/TextParsingTests.swift +0 -11
  514. package/Tests/RunicTests/UsageFormatterTests.swift +0 -111
  515. package/Tests/RunicTests/UsageLedgerAnomalyDetectionTests.swift +0 -170
  516. package/Tests/RunicTests/UsageLedgerForecastTests.swift +0 -211
  517. package/Tests/RunicTests/UsageLedgerInsightsAdvisorTests.swift +0 -81
  518. package/Tests/RunicTests/UsageLedgerProjectNameTests.swift +0 -168
  519. package/Tests/RunicTests/UsagePaceTests.swift +0 -76
  520. package/Tests/RunicTests/UsagePaceTextTests.swift +0 -108
  521. package/Tests/RunicTests/UsagePolicyEngineTests.swift +0 -89
  522. package/Tests/RunicTests/WidgetSnapshotTests.swift +0 -43
  523. package/Tests/RunicTests/ZaiProviderTests.swift +0 -59
  524. package/Tests/RunicTests/ZaiTokenStoreTestSupport.swift +0 -9
  525. package/TestsLinux/PlatformGatingTests.swift +0 -46
  526. package/appcast.xml +0 -104
  527. package/assets/logo-concept-stack.svg +0 -24
  528. package/assets/logo-minimal-bars.svg +0 -15
  529. package/assets/logo.svg +0 -20
  530. package/assets/logo2.svg +0 -43
  531. package/bin/docs-list +0 -5
  532. package/build-and-run.sh +0 -369
  533. package/docs/.nojekyll +0 -1
  534. package/docs/CNAME +0 -1
  535. package/docs/antigravity.md +0 -75
  536. package/docs/architecture.md +0 -32
  537. package/docs/claude.md +0 -93
  538. package/docs/cli-commands/integration_guide.md +0 -371
  539. package/docs/cli-commands/quick_reference.md +0 -362
  540. package/docs/cli-commands/readme.md +0 -361
  541. package/docs/cli.md +0 -156
  542. package/docs/cloudkit_sync_guide.md +0 -495
  543. package/docs/codebase_review.md +0 -288
  544. package/docs/codex-oauth.md +0 -635
  545. package/docs/codex.md +0 -104
  546. package/docs/codexbar.png +0 -0
  547. package/docs/copilot.md +0 -44
  548. package/docs/cursor.md +0 -46
  549. package/docs/design/designcomparisonchart.md +0 -510
  550. package/docs/design/implementationguide.md +0 -792
  551. package/docs/design/menubaricondesignconcepts.md +0 -796
  552. package/docs/design/mockups/hybridiconconcept.svg +0 -62
  553. package/docs/design/mockups/infinityiconconcept.svg +0 -41
  554. package/docs/design/mockups/infinityiconstates.svg +0 -129
  555. package/docs/design/mockups/wavelogorefined.svg +0 -48
  556. package/docs/design/quick_summary.md +0 -426
  557. package/docs/design/readme.md +0 -478
  558. package/docs/design/sizespecifications.md +0 -575
  559. package/docs/design-system.md +0 -836
  560. package/docs/factory.md +0 -103
  561. package/docs/gemini.md +0 -73
  562. package/docs/icon.md +0 -37
  563. package/docs/icon.png +0 -0
  564. package/docs/index.html +0 -175
  565. package/docs/keychain_fix.md +0 -274
  566. package/docs/minimax.md +0 -71
  567. package/docs/packaging.md +0 -25
  568. package/docs/progress-bar-improvements.md +0 -240
  569. package/docs/progress-bar-quick-reference.md +0 -283
  570. package/docs/progress-bar-technical-details.md +0 -432
  571. package/docs/progress-bar-visual-test.swift +0 -375
  572. package/docs/provider.md +0 -202
  573. package/docs/providers.md +0 -86
  574. package/docs/refactor/macros.md +0 -35
  575. package/docs/refresh-loop.md +0 -22
  576. package/docs/releasing-homebrew.md +0 -35
  577. package/docs/releasing.md +0 -121
  578. package/docs/research/concrete_todo_2026-02-22.md +0 -47
  579. package/docs/research/core-feature-research.md +0 -248
  580. package/docs/research/feature_uiux_roadmap_2026-02-22.md +0 -202
  581. package/docs/research/parity_matrix.md +0 -49
  582. package/docs/research/provider_expansion_candidates_2026-02-22.md +0 -80
  583. package/docs/research/provider_model_token_project_matrix_2026-02-23.md +0 -46
  584. package/docs/research/release_gate_checklist.md +0 -57
  585. package/docs/site.css +0 -505
  586. package/docs/sparkle.md +0 -28
  587. package/docs/status.md +0 -28
  588. package/docs/sync/implementation.md +0 -393
  589. package/docs/sync/readme.md +0 -317
  590. package/docs/sync_files_summary.md +0 -391
  591. package/docs/sync_quick_reference.md +0 -225
  592. package/docs/todo.md +0 -11
  593. package/docs/ui.md +0 -29
  594. package/docs/web-integration.md +0 -9
  595. package/docs/widgets.md +0 -85
  596. package/docs/workflows/error-handling-improvements.md +0 -434
  597. package/docs/workflows/folder_structure.md +0 -299
  598. package/docs/workflows/loading_states.md +0 -446
  599. package/docs/workflows/loading_states_examples.md +0 -565
  600. package/docs/workflows/loading_states_flow.md +0 -430
  601. package/docs/workflows/performance_optimizations.md +0 -457
  602. package/docs/workflows/phase1-cli-testing-report.md +0 -313
  603. package/docs/workflows/quick_reference.md +0 -228
  604. package/docs/workflows/readme.md +0 -59
  605. package/docs/workflows/recent_improvements.md +0 -275
  606. package/docs/workflows/sync_enablement_summary.md +0 -400
  607. package/docs/zai.md +0 -43
  608. package/runic.png +0 -0
  609. package/runic.svg +0 -15
  610. package/version.env +0 -2
@@ -1,1749 +0,0 @@
1
- import AppKit
2
- import Observation
3
- import RunicCore
4
- import ServiceManagement
5
-
6
- enum RefreshFrequency: String, CaseIterable, Identifiable {
7
- case manual
8
- case oneMinute
9
- case twoMinutes
10
- case fiveMinutes
11
- case fifteenMinutes
12
-
13
- var id: String {
14
- self.rawValue
15
- }
16
-
17
- var seconds: TimeInterval? {
18
- switch self {
19
- case .manual: nil
20
- case .oneMinute: 60
21
- case .twoMinutes: 120
22
- case .fiveMinutes: 300
23
- case .fifteenMinutes: 900
24
- }
25
- }
26
-
27
- var label: String {
28
- switch self {
29
- case .manual: "Manual"
30
- case .oneMinute: "1 min"
31
- case .twoMinutes: "2 min"
32
- case .fiveMinutes: "5 min"
33
- case .fifteenMinutes: "15 min"
34
- }
35
- }
36
- }
37
-
38
- enum UsageMetricDisplayMode: String, CaseIterable, Identifiable {
39
- case barsAndPercent
40
- case barsOnly
41
- case percentOnly
42
-
43
- var id: String {
44
- self.rawValue
45
- }
46
-
47
- var label: String {
48
- switch self {
49
- case .barsAndPercent: "Bars + %"
50
- case .barsOnly: "Bars"
51
- case .percentOnly: "%"
52
- }
53
- }
54
-
55
- var showsBars: Bool {
56
- switch self {
57
- case .barsAndPercent, .barsOnly:
58
- true
59
- case .percentOnly:
60
- false
61
- }
62
- }
63
-
64
- var showsPercent: Bool {
65
- switch self {
66
- case .barsAndPercent, .percentOnly:
67
- true
68
- case .barsOnly:
69
- false
70
- }
71
- }
72
- }
73
-
74
- enum MenuMode: String, CaseIterable, Identifiable {
75
- case glance
76
- case analyst
77
- case `operator`
78
-
79
- var id: String {
80
- self.rawValue
81
- }
82
-
83
- var label: String {
84
- switch self {
85
- case .glance:
86
- "Glance"
87
- case .analyst:
88
- "Analyst"
89
- case .operator:
90
- "Operator"
91
- }
92
- }
93
- }
94
-
95
- enum ChartStyle: String, CaseIterable, Identifiable {
96
- case line
97
- case area
98
- case bar
99
-
100
- var id: String {
101
- self.rawValue
102
- }
103
-
104
- var label: String {
105
- switch self {
106
- case .line: "Line"
107
- case .area: "Area"
108
- case .bar: "Bar"
109
- }
110
- }
111
- }
112
-
113
- enum NumberFormat: String, CaseIterable, Identifiable {
114
- case abbreviated
115
- case full
116
-
117
- var id: String {
118
- self.rawValue
119
- }
120
-
121
- var label: String {
122
- switch self {
123
- case .abbreviated: "Abbreviated"
124
- case .full: "Full"
125
- }
126
- }
127
- }
128
-
129
- enum DateFormat: String, CaseIterable, Identifiable {
130
- case relative
131
- case absolute
132
-
133
- var id: String {
134
- self.rawValue
135
- }
136
-
137
- var label: String {
138
- switch self {
139
- case .relative: "Relative"
140
- case .absolute: "Absolute"
141
- }
142
- }
143
- }
144
-
145
- enum Theme: String, CaseIterable, Identifiable {
146
- case system
147
- case light
148
- case dark
149
-
150
- var id: String {
151
- self.rawValue
152
- }
153
-
154
- var label: String {
155
- switch self {
156
- case .system: "System"
157
- case .light: "Light"
158
- case .dark: "Dark"
159
- }
160
- }
161
- }
162
-
163
- enum ProviderSwitcherLayout: String, CaseIterable, Identifiable {
164
- case top
165
- case sidebar
166
-
167
- var id: String {
168
- self.rawValue
169
- }
170
-
171
- var label: String {
172
- switch self {
173
- case .top: "Top"
174
- case .sidebar: "Sidebar"
175
- }
176
- }
177
- }
178
-
179
- enum ProviderSwitcherIconSize: String, CaseIterable, Identifiable {
180
- case small
181
- case medium
182
-
183
- var id: String {
184
- self.rawValue
185
- }
186
-
187
- var label: String {
188
- switch self {
189
- case .small: "Small"
190
- case .medium: "Medium"
191
- }
192
- }
193
- }
194
-
195
- @MainActor
196
- @Observable
197
- final class SettingsStore {
198
- /// Persisted provider display order.
199
- ///
200
- /// Stored as raw `UsageProvider` strings so new providers can be appended automatically without breaking.
201
- private var providerOrderRaw: [String] {
202
- didSet { self.userDefaults.set(self.providerOrderRaw, forKey: "providerOrder") }
203
- }
204
-
205
- var refreshFrequency: RefreshFrequency {
206
- didSet { self.userDefaults.set(self.refreshFrequency.rawValue, forKey: "refreshFrequency") }
207
- }
208
-
209
- var autoDisableRefreshWhenIdleEnabled: Bool {
210
- didSet { self.userDefaults.set(
211
- self.autoDisableRefreshWhenIdleEnabled,
212
- forKey: "autoDisableRefreshWhenIdleEnabled") }
213
- }
214
-
215
- var autoDisableRefreshWhenIdleMinutes: Int {
216
- didSet { self.userDefaults.set(
217
- self.autoDisableRefreshWhenIdleMinutes,
218
- forKey: "autoDisableRefreshWhenIdleMinutes") }
219
- }
220
-
221
- var autoDisableRefreshOnSleepEnabled: Bool {
222
- didSet {
223
- self.userDefaults.set(self.autoDisableRefreshOnSleepEnabled, forKey: "autoDisableRefreshOnSleepEnabled")
224
- }
225
- }
226
-
227
- var autoRefreshWarningEnabled: Bool {
228
- didSet { self.userDefaults.set(self.autoRefreshWarningEnabled, forKey: "autoRefreshWarningEnabled") }
229
- }
230
-
231
- var autoRefreshWarningThreshold: Int {
232
- didSet { self.userDefaults.set(self.autoRefreshWarningThreshold, forKey: "autoRefreshWarningThreshold") }
233
- }
234
-
235
- var autoSuspendInactiveProvidersEnabled: Bool {
236
- didSet {
237
- self.userDefaults.set(
238
- self.autoSuspendInactiveProvidersEnabled,
239
- forKey: "autoSuspendInactiveProvidersEnabled")
240
- }
241
- }
242
-
243
- var autoSuspendInactiveProvidersMinutes: Int {
244
- didSet {
245
- self.userDefaults.set(
246
- self.autoSuspendInactiveProvidersMinutes,
247
- forKey: "autoSuspendInactiveProvidersMinutes")
248
- }
249
- }
250
-
251
- var launchAtLogin: Bool {
252
- didSet {
253
- self.userDefaults.set(self.launchAtLogin, forKey: "launchAtLogin")
254
- LaunchAtLoginManager.setEnabled(self.launchAtLogin)
255
- }
256
- }
257
-
258
- /// Hidden toggle to reveal debug-only menu items (enable via defaults write com.sriinnu.athena.Runic
259
- /// debugMenuEnabled
260
- /// -bool YES).
261
- var debugMenuEnabled: Bool {
262
- didSet { self.userDefaults.set(self.debugMenuEnabled, forKey: "debugMenuEnabled") }
263
- }
264
-
265
- private var debugLoadingPatternRaw: String? {
266
- didSet {
267
- if let raw = self.debugLoadingPatternRaw {
268
- self.userDefaults.set(raw, forKey: "debugLoadingPattern")
269
- } else {
270
- self.userDefaults.removeObject(forKey: "debugLoadingPattern")
271
- }
272
- }
273
- }
274
-
275
- var statusChecksEnabled: Bool {
276
- didSet { self.userDefaults.set(self.statusChecksEnabled, forKey: "statusChecksEnabled") }
277
- }
278
-
279
- var sessionQuotaNotificationsEnabled: Bool {
280
- didSet {
281
- self.userDefaults.set(self.sessionQuotaNotificationsEnabled, forKey: "sessionQuotaNotificationsEnabled")
282
- }
283
- }
284
-
285
- /// When enabled, post macOS notifications when spend forecasts breach project budgets.
286
- var budgetNotificationsEnabled: Bool {
287
- didSet {
288
- self.userDefaults.set(self.budgetNotificationsEnabled, forKey: "budgetNotificationsEnabled")
289
- }
290
- }
291
-
292
- /// When enabled, progress bars show "percent used" instead of "percent left".
293
- var usageBarsShowUsed: Bool {
294
- didSet { self.userDefaults.set(self.usageBarsShowUsed, forKey: "usageBarsShowUsed") }
295
- }
296
-
297
- var usageMetricDisplayMode: UsageMetricDisplayMode {
298
- didSet {
299
- self.userDefaults.set(self.usageMetricDisplayMode.rawValue, forKey: "usageMetricDisplayMode")
300
- }
301
- }
302
-
303
- var menuMode: MenuMode {
304
- didSet {
305
- self.userDefaults.set(self.menuMode.rawValue, forKey: "menuMode")
306
- }
307
- }
308
-
309
- var chartStyle: ChartStyle {
310
- didSet { self.userDefaults.set(self.chartStyle.rawValue, forKey: "chartStyle") }
311
- }
312
-
313
- var numberFormat: NumberFormat {
314
- didSet { self.userDefaults.set(self.numberFormat.rawValue, forKey: "numberFormat") }
315
- }
316
-
317
- var dateFormat: DateFormat {
318
- didSet { self.userDefaults.set(self.dateFormat.rawValue, forKey: "dateFormat") }
319
- }
320
-
321
- var theme: Theme {
322
- didSet {
323
- self.userDefaults.set(self.theme.rawValue, forKey: "theme")
324
- RunicApp.applyTheme(self.theme)
325
- }
326
- }
327
-
328
- var selectedFontFamily: String {
329
- didSet {
330
- self.userDefaults.set(self.selectedFontFamily, forKey: "selectedFontFamily")
331
- RunicFont.family = self.selectedFontFamily
332
- }
333
- }
334
-
335
- /// Optional: use provider branding icons with a percentage in the menu bar.
336
- var menuBarShowsBrandIconWithPercent: Bool {
337
- didSet {
338
- self.userDefaults.set(self.menuBarShowsBrandIconWithPercent, forKey: "menuBarShowsBrandIconWithPercent")
339
- }
340
- }
341
-
342
- /// Optional: render the menu bar icon with a vibrant, data-reactive color.
343
- var menuBarVibrantIconEnabled: Bool {
344
- didSet {
345
- self.userDefaults.set(self.menuBarVibrantIconEnabled, forKey: "menuBarVibrantIconEnabled")
346
- }
347
- }
348
-
349
- /// Optional: show provider cost summary from local usage logs (Codex + Claude).
350
- var costUsageEnabled: Bool {
351
- didSet { self.userDefaults.set(self.costUsageEnabled, forKey: "tokenCostUsageEnabled") }
352
- }
353
-
354
- /// Optional: limit how many insight rows appear in the menu before "More…".
355
- var insightsMenuMaxItems: Int {
356
- didSet { self.userDefaults.set(self.insightsMenuMaxItems, forKey: "insightsMenuMaxItems") }
357
- }
358
-
359
- /// Optional: how many days to include in the insights report.
360
- var insightsReportDays: Int {
361
- didSet { self.userDefaults.set(self.insightsReportDays, forKey: "insightsReportDays") }
362
- }
363
-
364
- /// How many days of usage history to scan for ledger data (charts, breakdowns).
365
- /// Options: 3, 7, 30, 365. Default: 30.
366
- var ledgerMaxAgeDays: Int {
367
- didSet { self.userDefaults.set(self.ledgerMaxAgeDays, forKey: "ledgerMaxAgeDays") }
368
- }
369
-
370
- var randomBlinkEnabled: Bool {
371
- didSet { self.userDefaults.set(self.randomBlinkEnabled, forKey: "randomBlinkEnabled") }
372
- }
373
-
374
- /// Optional: augment Claude usage with claude.ai web API (via browser cookies),
375
- /// incl. "Extra usage" spend.
376
- var claudeWebExtrasEnabled: Bool {
377
- didSet { self.userDefaults.set(self.claudeWebExtrasEnabled, forKey: "claudeWebExtrasEnabled") }
378
- }
379
-
380
- /// Optional: show Codex credits + Claude extra usage sections in the menu UI.
381
- var showOptionalCreditsAndExtraUsage: Bool {
382
- didSet {
383
- self.userDefaults.set(self.showOptionalCreditsAndExtraUsage, forKey: "showOptionalCreditsAndExtraUsage")
384
- }
385
- }
386
-
387
- /// Optional: fetch OpenAI web dashboard extras for Codex (browser cookies).
388
- var openAIWebAccessEnabled: Bool {
389
- didSet { self.userDefaults.set(self.openAIWebAccessEnabled, forKey: "openAIWebAccessEnabled") }
390
- }
391
-
392
- private var codexUsageDataSourceRaw: String? {
393
- didSet {
394
- if let raw = self.codexUsageDataSourceRaw {
395
- self.userDefaults.set(raw, forKey: "codexUsageDataSource")
396
- } else {
397
- self.userDefaults.removeObject(forKey: "codexUsageDataSource")
398
- }
399
- }
400
- }
401
-
402
- private var claudeUsageDataSourceRaw: String? {
403
- didSet {
404
- if let raw = self.claudeUsageDataSourceRaw {
405
- self.userDefaults.set(raw, forKey: "claudeUsageDataSource")
406
- } else {
407
- self.userDefaults.removeObject(forKey: "claudeUsageDataSource")
408
- }
409
- }
410
- }
411
-
412
- /// Optional: collapse provider icons into a single menu bar item with an in-menu switcher.
413
- var mergeIcons: Bool {
414
- didSet { self.userDefaults.set(self.mergeIcons, forKey: "mergeIcons") }
415
- }
416
-
417
- /// Optional: show provider icons in the in-menu switcher.
418
- var switcherShowsIcons: Bool {
419
- didSet { self.userDefaults.set(self.switcherShowsIcons, forKey: "switcherShowsIcons") }
420
- }
421
-
422
- /// Optional: position the provider switcher either on top or in a left sidebar.
423
- var providerSwitcherLayout: ProviderSwitcherLayout {
424
- didSet {
425
- self.userDefaults.set(self.providerSwitcherLayout.rawValue, forKey: "providerSwitcherLayout")
426
- }
427
- }
428
-
429
- /// Optional: size of provider icons in the switcher.
430
- var providerSwitcherIconSize: ProviderSwitcherIconSize {
431
- didSet {
432
- self.userDefaults.set(self.providerSwitcherIconSize.rawValue, forKey: "providerSwitcherIconSize")
433
- }
434
- }
435
-
436
- /// Show the built-in providers pane as a sidebar (true) or flat list (false).
437
- var providersPaneSidebar: Bool {
438
- didSet { self.userDefaults.set(self.providersPaneSidebar, forKey: "providersPaneSidebar") }
439
- }
440
-
441
- /// z.ai API token (stored in Keychain).
442
- var zaiAPIToken: String {
443
- didSet {
444
- self.schedulePersistZaiAPIToken()
445
- if !self.zaiAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
446
- self.autoEnableProviderIfNeeded(cliName: "zai")
447
- }
448
- }
449
- }
450
-
451
- /// MiniMax API token (stored in Keychain).
452
- var minimaxAPIToken: String {
453
- didSet {
454
- self.schedulePersistMiniMaxAPIToken()
455
- if !self.minimaxAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
456
- self.autoEnableProviderIfNeeded(cliName: "minimax")
457
- }
458
- }
459
- }
460
-
461
- /// MiniMax manual Cookie header (stored in Keychain).
462
- var minimaxCookieHeader: String {
463
- didSet {
464
- self.schedulePersistMiniMaxCookieHeader()
465
- if !self.minimaxCookieHeader.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
466
- self.autoEnableProviderIfNeeded(cliName: "minimax")
467
- }
468
- }
469
- }
470
-
471
- /// MiniMax Group ID (stored in Keychain).
472
- var minimaxGroupID: String {
473
- didSet { self.schedulePersistMiniMaxGroupID() }
474
- }
475
-
476
- /// Copilot API token (stored in Keychain).
477
- var copilotAPIToken: String {
478
- didSet {
479
- self.schedulePersistCopilotAPIToken()
480
- if !self.copilotAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
481
- self.autoEnableProviderIfNeeded(cliName: "copilot")
482
- }
483
- }
484
- }
485
-
486
- /// OpenRouter API key (stored in Keychain).
487
- var openRouterAPIToken: String {
488
- didSet {
489
- self.schedulePersistOpenRouterAPIToken()
490
- if !self.openRouterAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
491
- self.autoEnableProviderIfNeeded(cliName: "openrouter")
492
- }
493
- }
494
- }
495
-
496
- /// Groq API key (stored in Keychain).
497
- var groqAPIToken: String {
498
- didSet {
499
- self.schedulePersistGroqAPIToken()
500
- if !self.groqAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
501
- self.autoEnableProviderIfNeeded(cliName: "groq")
502
- }
503
- }
504
- }
505
-
506
- /// DeepSeek API key (stored in Keychain).
507
- var deepSeekAPIToken: String {
508
- didSet {
509
- self.schedulePersistDeepSeekAPIToken()
510
- if !self.deepSeekAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
511
- self.autoEnableProviderIfNeeded(cliName: "deepseek")
512
- }
513
- }
514
- }
515
-
516
- /// Fireworks API key (stored in Keychain).
517
- var fireworksAPIToken: String {
518
- didSet {
519
- self.schedulePersistFireworksAPIToken()
520
- if !self.fireworksAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
521
- self.autoEnableProviderIfNeeded(cliName: "fireworks")
522
- }
523
- }
524
- }
525
-
526
- /// Mistral API key (stored in Keychain).
527
- var mistralAPIToken: String {
528
- didSet {
529
- self.schedulePersistMistralAPIToken()
530
- if !self.mistralAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
531
- self.autoEnableProviderIfNeeded(cliName: "mistral")
532
- }
533
- }
534
- }
535
-
536
- /// Perplexity API key (stored in Keychain).
537
- var perplexityAPIToken: String {
538
- didSet {
539
- self.schedulePersistPerplexityAPIToken()
540
- if !self.perplexityAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
541
- self.autoEnableProviderIfNeeded(cliName: "perplexity")
542
- }
543
- }
544
- }
545
-
546
- /// Kimi API key (stored in Keychain).
547
- var kimiAPIToken: String {
548
- didSet {
549
- self.schedulePersistKimiAPIToken()
550
- if !self.kimiAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
551
- self.autoEnableProviderIfNeeded(cliName: "kimi")
552
- }
553
- }
554
- }
555
-
556
- /// Auggie API token (stored in Keychain).
557
- var auggieAPIToken: String {
558
- didSet {
559
- self.schedulePersistAuggieAPIToken()
560
- if !self.auggieAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
561
- self.autoEnableProviderIfNeeded(cliName: "auggie")
562
- }
563
- }
564
- }
565
-
566
- /// Together API key (stored in Keychain).
567
- var togetherAPIToken: String {
568
- didSet {
569
- self.schedulePersistTogetherAPIToken()
570
- if !self.togetherAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
571
- self.autoEnableProviderIfNeeded(cliName: "together")
572
- }
573
- }
574
- }
575
-
576
- /// Cohere API key (stored in Keychain).
577
- var cohereAPIToken: String {
578
- didSet {
579
- self.schedulePersistCohereAPIToken()
580
- if !self.cohereAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
581
- self.autoEnableProviderIfNeeded(cliName: "cohere")
582
- }
583
- }
584
- }
585
-
586
- /// xAI API key (stored in Keychain).
587
- var xaiAPIToken: String {
588
- didSet {
589
- self.schedulePersistXAiAPIToken()
590
- if !self.xaiAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
591
- self.autoEnableProviderIfNeeded(cliName: "xai")
592
- }
593
- }
594
- }
595
-
596
- /// Cerebras API key (stored in Keychain).
597
- var cerebrasAPIToken: String {
598
- didSet {
599
- self.schedulePersistCerebrasAPIToken()
600
- if !self.cerebrasAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
601
- self.autoEnableProviderIfNeeded(cliName: "cerebras")
602
- }
603
- }
604
- }
605
-
606
- /// Qwen DashScope API key (stored in Keychain).
607
- var qwenAPIToken: String {
608
- didSet {
609
- self.schedulePersistQwenAPIToken()
610
- if !self.qwenAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
611
- self.autoEnableProviderIfNeeded(cliName: "qwen")
612
- }
613
- }
614
- }
615
-
616
- /// SambaNova API key (stored in Keychain).
617
- var sambaNovaAPIToken: String {
618
- didSet {
619
- self.schedulePersistSambaNovaAPIToken()
620
- if !self.sambaNovaAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
621
- self.autoEnableProviderIfNeeded(cliName: "sambanova")
622
- }
623
- }
624
- }
625
-
626
- /// Azure OpenAI endpoint URL (stored in UserDefaults).
627
- var azureOpenAIEndpoint: String {
628
- didSet { self.userDefaults.set(self.azureOpenAIEndpoint, forKey: "azureOpenAIEndpoint") }
629
- }
630
-
631
- /// Azure OpenAI deployment name (stored in UserDefaults).
632
- var azureOpenAIDeployment: String {
633
- didSet { self.userDefaults.set(self.azureOpenAIDeployment, forKey: "azureOpenAIDeployment") }
634
- }
635
-
636
- /// Azure OpenAI API version (stored in UserDefaults).
637
- var azureOpenAIAPIVersion: String {
638
- didSet { self.userDefaults.set(self.azureOpenAIAPIVersion, forKey: "azureOpenAIAPIVersion") }
639
- }
640
-
641
- /// Azure OpenAI API key (stored in Keychain).
642
- var azureOpenAIAPIToken: String {
643
- didSet {
644
- self.schedulePersistAzureOpenAIAPIToken()
645
- if !self.azureOpenAIAPIToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
646
- self.autoEnableProviderIfNeeded(cliName: "azure")
647
- }
648
- }
649
- }
650
-
651
- /// Amazon Bedrock region (stored in UserDefaults).
652
- var bedrockRegion: String {
653
- didSet { self.userDefaults.set(self.bedrockRegion, forKey: "bedrockRegion") }
654
- }
655
-
656
- /// Optional AWS profile for Amazon Bedrock (stored in UserDefaults).
657
- var bedrockAWSProfile: String {
658
- didSet { self.userDefaults.set(self.bedrockAWSProfile, forKey: "bedrockAWSProfile") }
659
- }
660
-
661
- /// Optional model filter for Amazon Bedrock (stored in UserDefaults).
662
- var bedrockModelID: String {
663
- didSet { self.userDefaults.set(self.bedrockModelID, forKey: "bedrockModelID") }
664
- }
665
-
666
- /// Google Cloud project for Vertex AI (stored in UserDefaults).
667
- var vertexaiProject: String {
668
- didSet { self.userDefaults.set(self.vertexaiProject, forKey: "vertexaiProject") }
669
- }
670
-
671
- /// Google Cloud location/region for Vertex AI (stored in UserDefaults).
672
- var vertexaiLocation: String {
673
- didSet { self.userDefaults.set(self.vertexaiLocation, forKey: "vertexaiLocation") }
674
- }
675
-
676
- private var selectedMenuProviderRaw: String? {
677
- didSet {
678
- if let raw = self.selectedMenuProviderRaw {
679
- self.userDefaults.set(raw, forKey: "selectedMenuProvider")
680
- } else {
681
- self.userDefaults.removeObject(forKey: "selectedMenuProvider")
682
- }
683
- }
684
- }
685
-
686
- /// Optional override for the loading animation pattern, exposed via the Debug tab.
687
- var debugLoadingPattern: LoadingPattern? {
688
- get { self.debugLoadingPatternRaw.flatMap(LoadingPattern.init(rawValue:)) }
689
- set {
690
- self.debugLoadingPatternRaw = newValue?.rawValue
691
- }
692
- }
693
-
694
- var selectedMenuProvider: UsageProvider? {
695
- get { self.selectedMenuProviderRaw.flatMap(UsageProvider.init(rawValue:)) }
696
- set {
697
- self.selectedMenuProviderRaw = newValue?.rawValue
698
- }
699
- }
700
-
701
- var codexUsageDataSource: CodexUsageDataSource {
702
- get { CodexUsageDataSource(rawValue: self.codexUsageDataSourceRaw ?? "") ?? .oauth }
703
- set {
704
- self.codexUsageDataSourceRaw = newValue.rawValue
705
- }
706
- }
707
-
708
- var claudeUsageDataSource: ClaudeUsageDataSource {
709
- get { ClaudeUsageDataSource(rawValue: self.claudeUsageDataSourceRaw ?? "") ?? .oauth }
710
- set {
711
- self.claudeUsageDataSourceRaw = newValue.rawValue
712
- if newValue != .cli {
713
- self.claudeWebExtrasEnabled = false
714
- }
715
- }
716
- }
717
-
718
- var menuObservationToken: Int {
719
- _ = self.providerOrderRaw
720
- _ = self.refreshFrequency
721
- _ = self.autoDisableRefreshWhenIdleEnabled
722
- _ = self.autoDisableRefreshWhenIdleMinutes
723
- _ = self.autoDisableRefreshOnSleepEnabled
724
- _ = self.autoRefreshWarningEnabled
725
- _ = self.autoRefreshWarningThreshold
726
- _ = self.autoSuspendInactiveProvidersEnabled
727
- _ = self.autoSuspendInactiveProvidersMinutes
728
- _ = self.launchAtLogin
729
- _ = self.debugMenuEnabled
730
- _ = self.statusChecksEnabled
731
- _ = self.sessionQuotaNotificationsEnabled
732
- _ = self.usageBarsShowUsed
733
- _ = self.usageMetricDisplayMode
734
- _ = self.menuMode
735
- _ = self.chartStyle
736
- _ = self.numberFormat
737
- _ = self.dateFormat
738
- _ = self.theme
739
- _ = self.menuBarShowsBrandIconWithPercent
740
- _ = self.menuBarVibrantIconEnabled
741
- _ = self.costUsageEnabled
742
- _ = self.insightsMenuMaxItems
743
- _ = self.insightsReportDays
744
- _ = self.ledgerMaxAgeDays
745
- _ = self.randomBlinkEnabled
746
- _ = self.claudeWebExtrasEnabled
747
- _ = self.showOptionalCreditsAndExtraUsage
748
- _ = self.openAIWebAccessEnabled
749
- _ = self.codexUsageDataSource
750
- _ = self.claudeUsageDataSource
751
- _ = self.mergeIcons
752
- _ = self.switcherShowsIcons
753
- _ = self.providerSwitcherLayout
754
- _ = self.providerSwitcherIconSize
755
- _ = self.zaiAPIToken
756
- _ = self.minimaxAPIToken
757
- _ = self.minimaxCookieHeader
758
- _ = self.minimaxGroupID
759
- _ = self.copilotAPIToken
760
- _ = self.openRouterAPIToken
761
- _ = self.groqAPIToken
762
- _ = self.deepSeekAPIToken
763
- _ = self.fireworksAPIToken
764
- _ = self.mistralAPIToken
765
- _ = self.perplexityAPIToken
766
- _ = self.kimiAPIToken
767
- _ = self.auggieAPIToken
768
- _ = self.togetherAPIToken
769
- _ = self.cohereAPIToken
770
- _ = self.xaiAPIToken
771
- _ = self.cerebrasAPIToken
772
- _ = self.qwenAPIToken
773
- _ = self.sambaNovaAPIToken
774
- _ = self.azureOpenAIEndpoint
775
- _ = self.azureOpenAIDeployment
776
- _ = self.azureOpenAIAPIVersion
777
- _ = self.azureOpenAIAPIToken
778
- _ = self.bedrockRegion
779
- _ = self.bedrockAWSProfile
780
- _ = self.bedrockModelID
781
- _ = self.vertexaiProject
782
- _ = self.vertexaiLocation
783
- _ = self.debugLoadingPattern
784
- _ = self.selectedMenuProvider
785
- _ = self.providerToggleRevision
786
- return 0
787
- }
788
-
789
- private var providerDetectionCompleted: Bool {
790
- didSet { self.userDefaults.set(self.providerDetectionCompleted, forKey: "providerDetectionCompleted") }
791
- }
792
-
793
- @ObservationIgnored private let userDefaults: UserDefaults
794
- @ObservationIgnored private let toggleStore: ProviderToggleStore
795
- @ObservationIgnored private let zaiTokenStore: any ZaiTokenStoring
796
- @ObservationIgnored private var zaiTokenPersistTask: Task<Void, Never>?
797
- @ObservationIgnored private let minimaxTokenStore: any MiniMaxTokenStoring
798
- @ObservationIgnored private var minimaxTokenPersistTask: Task<Void, Never>?
799
- @ObservationIgnored private let minimaxCookieHeaderStore: any MiniMaxCookieHeaderStoring
800
- @ObservationIgnored private var minimaxCookieHeaderPersistTask: Task<Void, Never>?
801
- @ObservationIgnored private let minimaxGroupIDStore: any MiniMaxGroupIDStoring
802
- @ObservationIgnored private var minimaxGroupIDPersistTask: Task<Void, Never>?
803
- @ObservationIgnored private let copilotTokenStore: any CopilotTokenStoring
804
- @ObservationIgnored private var copilotTokenPersistTask: Task<Void, Never>?
805
- @ObservationIgnored private let openRouterTokenStore: any OpenRouterTokenStoring
806
- @ObservationIgnored private var openRouterTokenPersistTask: Task<Void, Never>?
807
- @ObservationIgnored private let groqTokenStore: any GroqTokenStoring
808
- @ObservationIgnored private var groqTokenPersistTask: Task<Void, Never>?
809
- @ObservationIgnored private let deepSeekTokenStore: any DeepSeekTokenStoring
810
- @ObservationIgnored private var deepSeekTokenPersistTask: Task<Void, Never>?
811
- @ObservationIgnored private let fireworksTokenStore: any FireworksTokenStoring
812
- @ObservationIgnored private var fireworksTokenPersistTask: Task<Void, Never>?
813
- @ObservationIgnored private let mistralTokenStore: any MistralTokenStoring
814
- @ObservationIgnored private var mistralTokenPersistTask: Task<Void, Never>?
815
- @ObservationIgnored private let perplexityTokenStore: any PerplexityTokenStoring
816
- @ObservationIgnored private var perplexityTokenPersistTask: Task<Void, Never>?
817
- @ObservationIgnored private let kimiTokenStore: any KimiTokenStoring
818
- @ObservationIgnored private var kimiTokenPersistTask: Task<Void, Never>?
819
- @ObservationIgnored private let auggieTokenStore: any AuggieTokenStoring
820
- @ObservationIgnored private var auggieTokenPersistTask: Task<Void, Never>?
821
- @ObservationIgnored private let togetherTokenStore: any TogetherTokenStoring
822
- @ObservationIgnored private var togetherTokenPersistTask: Task<Void, Never>?
823
- @ObservationIgnored private let cohereTokenStore: any CohereTokenStoring
824
- @ObservationIgnored private var cohereTokenPersistTask: Task<Void, Never>?
825
- @ObservationIgnored private let xaiTokenStore: any XAITokenStoring
826
- @ObservationIgnored private var xaiTokenPersistTask: Task<Void, Never>?
827
- @ObservationIgnored private let cerebrasTokenStore: any CerebrasTokenStoring
828
- @ObservationIgnored private var cerebrasTokenPersistTask: Task<Void, Never>?
829
- @ObservationIgnored private let sambaNovaTokenStore: any SambaNovaTokenStoring
830
- @ObservationIgnored private var sambaNovaTokenPersistTask: Task<Void, Never>?
831
- @ObservationIgnored private let qwenTokenStore: any QwenTokenStoring
832
- @ObservationIgnored private var qwenTokenPersistTask: Task<Void, Never>?
833
- @ObservationIgnored private let azureOpenAITokenStore: any AzureOpenAITokenStoring
834
- @ObservationIgnored private var azureOpenAITokenPersistTask: Task<Void, Never>?
835
- // Cache enablement so tight UI loops (menu bar animations) don't hit UserDefaults each tick.
836
- @ObservationIgnored private var cachedProviderEnablement: [UsageProvider: Bool] = [:]
837
- @ObservationIgnored private var cachedProviderEnablementRevision: Int = -1
838
- @ObservationIgnored private var cachedEnabledProviders: [UsageProvider] = []
839
- @ObservationIgnored private var cachedEnabledProvidersRevision: Int = -1
840
- @ObservationIgnored private var cachedEnabledProvidersOrderRaw: [String] = []
841
- // Cache order to avoid re-building sets/arrays every animation tick.
842
- @ObservationIgnored private var cachedProviderOrder: [UsageProvider] = []
843
- @ObservationIgnored private var cachedProviderOrderRaw: [String] = []
844
- private var providerToggleRevision: Int = 0
845
-
846
- init(
847
- userDefaults: UserDefaults = .standard,
848
- zaiTokenStore: any ZaiTokenStoring = KeychainZaiTokenStore(),
849
- minimaxTokenStore: any MiniMaxTokenStoring = KeychainMiniMaxTokenStore(),
850
- minimaxCookieHeaderStore: any MiniMaxCookieHeaderStoring = KeychainMiniMaxCookieHeaderStore(),
851
- minimaxGroupIDStore: any MiniMaxGroupIDStoring = KeychainMiniMaxGroupIDStore(),
852
- copilotTokenStore: any CopilotTokenStoring = KeychainCopilotTokenStore(),
853
- openRouterTokenStore: any OpenRouterTokenStoring = KeychainOpenRouterTokenStore(),
854
- groqTokenStore: any GroqTokenStoring = KeychainGroqTokenStore(),
855
- deepSeekTokenStore: any DeepSeekTokenStoring = KeychainDeepSeekTokenStore(),
856
- fireworksTokenStore: any FireworksTokenStoring = KeychainFireworksTokenStore(),
857
- mistralTokenStore: any MistralTokenStoring = KeychainMistralTokenStore(),
858
- perplexityTokenStore: any PerplexityTokenStoring = KeychainPerplexityTokenStore(),
859
- kimiTokenStore: any KimiTokenStoring = KeychainKimiTokenStore(),
860
- auggieTokenStore: any AuggieTokenStoring = KeychainAuggieTokenStore(),
861
- togetherTokenStore: any TogetherTokenStoring = KeychainTogetherTokenStore(),
862
- cohereTokenStore: any CohereTokenStoring = KeychainCohereTokenStore(),
863
- xaiTokenStore: any XAITokenStoring = KeychainXAITokenStore(),
864
- cerebrasTokenStore: any CerebrasTokenStoring = KeychainCerebrasTokenStore(),
865
- sambaNovaTokenStore: any SambaNovaTokenStoring = KeychainSambaNovaTokenStore(),
866
- qwenTokenStore: any QwenTokenStoring = KeychainQwenTokenStore(),
867
- azureOpenAITokenStore: any AzureOpenAITokenStoring = KeychainAzureOpenAITokenStore())
868
- {
869
- self.userDefaults = userDefaults
870
- self.zaiTokenStore = zaiTokenStore
871
- self.minimaxTokenStore = minimaxTokenStore
872
- self.minimaxCookieHeaderStore = minimaxCookieHeaderStore
873
- self.minimaxGroupIDStore = minimaxGroupIDStore
874
- self.copilotTokenStore = copilotTokenStore
875
- self.openRouterTokenStore = openRouterTokenStore
876
- self.groqTokenStore = groqTokenStore
877
- self.deepSeekTokenStore = deepSeekTokenStore
878
- self.fireworksTokenStore = fireworksTokenStore
879
- self.mistralTokenStore = mistralTokenStore
880
- self.perplexityTokenStore = perplexityTokenStore
881
- self.kimiTokenStore = kimiTokenStore
882
- self.auggieTokenStore = auggieTokenStore
883
- self.togetherTokenStore = togetherTokenStore
884
- self.cohereTokenStore = cohereTokenStore
885
- self.xaiTokenStore = xaiTokenStore
886
- self.cerebrasTokenStore = cerebrasTokenStore
887
- self.sambaNovaTokenStore = sambaNovaTokenStore
888
- self.qwenTokenStore = qwenTokenStore
889
- self.azureOpenAITokenStore = azureOpenAITokenStore
890
- self.providerOrderRaw = userDefaults.stringArray(forKey: "providerOrder") ?? []
891
- let raw = userDefaults.string(forKey: "refreshFrequency") ?? RefreshFrequency.manual.rawValue
892
- self.refreshFrequency = RefreshFrequency(rawValue: raw) ?? .manual
893
- self.autoDisableRefreshWhenIdleEnabled = userDefaults.object(
894
- forKey: "autoDisableRefreshWhenIdleEnabled") as? Bool ?? true
895
- self.autoDisableRefreshWhenIdleMinutes = userDefaults.object(
896
- forKey: "autoDisableRefreshWhenIdleMinutes") as? Int ?? 5
897
- self.autoDisableRefreshOnSleepEnabled = userDefaults.object(
898
- forKey: "autoDisableRefreshOnSleepEnabled") as? Bool ?? true
899
- self.autoRefreshWarningEnabled = userDefaults.object(
900
- forKey: "autoRefreshWarningEnabled") as? Bool ?? true
901
- self.autoRefreshWarningThreshold = userDefaults.object(
902
- forKey: "autoRefreshWarningThreshold") as? Int ?? 10
903
- self.autoSuspendInactiveProvidersEnabled = userDefaults.object(
904
- forKey: "autoSuspendInactiveProvidersEnabled") as? Bool ?? true
905
- self.autoSuspendInactiveProvidersMinutes = userDefaults.object(
906
- forKey: "autoSuspendInactiveProvidersMinutes") as? Int ?? 720
907
- self.launchAtLogin = userDefaults.object(forKey: "launchAtLogin") as? Bool ?? false
908
- self.debugMenuEnabled = userDefaults.object(forKey: "debugMenuEnabled") as? Bool ?? false
909
- self.debugLoadingPatternRaw = userDefaults.string(forKey: "debugLoadingPattern")
910
- self.statusChecksEnabled = userDefaults.object(forKey: "statusChecksEnabled") as? Bool ?? true
911
- let sessionQuotaNotificationsDefault = userDefaults.object(
912
- forKey: "sessionQuotaNotificationsEnabled") as? Bool
913
- self.sessionQuotaNotificationsEnabled = sessionQuotaNotificationsDefault ?? true
914
- if sessionQuotaNotificationsDefault == nil {
915
- self.userDefaults.set(true, forKey: "sessionQuotaNotificationsEnabled")
916
- }
917
- self.budgetNotificationsEnabled = userDefaults.object(
918
- forKey: "budgetNotificationsEnabled") as? Bool ?? false
919
- self.usageBarsShowUsed = userDefaults.object(forKey: "usageBarsShowUsed") as? Bool ?? true
920
- let metricDisplayRaw = userDefaults.string(forKey: "usageMetricDisplayMode")
921
- self.usageMetricDisplayMode = UsageMetricDisplayMode(rawValue: metricDisplayRaw ?? "") ?? .barsAndPercent
922
- let menuModeRaw = userDefaults.string(forKey: "menuMode")
923
- self.menuMode = MenuMode(rawValue: menuModeRaw ?? "") ?? .operator
924
- let chartStyleRaw = userDefaults.string(forKey: "chartStyle")
925
- self.chartStyle = ChartStyle(rawValue: chartStyleRaw ?? "") ?? .line
926
- let numberFormatRaw = userDefaults.string(forKey: "numberFormat")
927
- self.numberFormat = NumberFormat(rawValue: numberFormatRaw ?? "") ?? .abbreviated
928
- let dateFormatRaw = userDefaults.string(forKey: "dateFormat")
929
- self.dateFormat = DateFormat(rawValue: dateFormatRaw ?? "") ?? .relative
930
- let themeRaw = userDefaults.string(forKey: "theme")
931
- self.theme = Theme(rawValue: themeRaw ?? "") ?? .system
932
- self.selectedFontFamily = userDefaults.string(forKey: "selectedFontFamily") ?? "Fira Code"
933
- self.menuBarShowsBrandIconWithPercent = userDefaults.object(
934
- forKey: "menuBarShowsBrandIconWithPercent") as? Bool ?? false
935
- self.menuBarVibrantIconEnabled = userDefaults.object(
936
- forKey: "menuBarVibrantIconEnabled") as? Bool ?? true
937
- self.costUsageEnabled = userDefaults.object(forKey: "tokenCostUsageEnabled") as? Bool ?? true
938
- self.insightsMenuMaxItems = userDefaults.object(forKey: "insightsMenuMaxItems") as? Int ?? 4
939
- self.insightsReportDays = userDefaults.object(forKey: "insightsReportDays") as? Int ?? 7
940
- self.ledgerMaxAgeDays = userDefaults.object(forKey: "ledgerMaxAgeDays") as? Int ?? 30
941
- self.randomBlinkEnabled = userDefaults.object(forKey: "randomBlinkEnabled") as? Bool ?? false
942
- self.claudeWebExtrasEnabled = userDefaults.object(forKey: "claudeWebExtrasEnabled") as? Bool ?? false
943
- let creditsExtrasDefault = userDefaults.object(forKey: "showOptionalCreditsAndExtraUsage") as? Bool
944
- self.showOptionalCreditsAndExtraUsage = creditsExtrasDefault ?? true
945
- if creditsExtrasDefault == nil {
946
- self.userDefaults.set(true, forKey: "showOptionalCreditsAndExtraUsage")
947
- }
948
- let openAIWebAccessDefault = userDefaults.object(forKey: "openAIWebAccessEnabled") as? Bool
949
- self.openAIWebAccessEnabled = openAIWebAccessDefault ?? true
950
- if openAIWebAccessDefault == nil {
951
- self.userDefaults.set(true, forKey: "openAIWebAccessEnabled")
952
- }
953
- let codexSourceRaw = userDefaults.string(forKey: "codexUsageDataSource")
954
- self.codexUsageDataSourceRaw = codexSourceRaw ?? CodexUsageDataSource.oauth.rawValue
955
- let claudeSourceRaw = userDefaults.string(forKey: "claudeUsageDataSource")
956
- self.claudeUsageDataSourceRaw = claudeSourceRaw ?? ClaudeUsageDataSource.oauth.rawValue
957
- self.mergeIcons = userDefaults.object(forKey: "mergeIcons") as? Bool ?? true
958
- self.switcherShowsIcons = userDefaults.object(forKey: "switcherShowsIcons") as? Bool ?? true
959
- let layoutRaw = userDefaults.string(forKey: "providerSwitcherLayout")
960
- self.providerSwitcherLayout = ProviderSwitcherLayout(rawValue: layoutRaw ?? "") ?? .top
961
- let iconSizeRaw = userDefaults.string(forKey: "providerSwitcherIconSize")
962
- self.providerSwitcherIconSize = ProviderSwitcherIconSize(rawValue: iconSizeRaw ?? "") ?? .medium
963
- self.providersPaneSidebar = userDefaults.object(forKey: "providersPaneSidebar") as? Bool ?? false
964
- self.azureOpenAIEndpoint = userDefaults.string(forKey: "azureOpenAIEndpoint") ?? ""
965
- self.azureOpenAIDeployment = userDefaults.string(forKey: "azureOpenAIDeployment") ?? ""
966
- self.azureOpenAIAPIVersion = userDefaults.string(forKey: "azureOpenAIAPIVersion")
967
- ?? "2024-10-21"
968
- self.bedrockRegion = userDefaults.string(forKey: "bedrockRegion") ?? ""
969
- self.bedrockAWSProfile = userDefaults.string(forKey: "bedrockAWSProfile") ?? ""
970
- self.bedrockModelID = userDefaults.string(forKey: "bedrockModelID") ?? ""
971
- self.vertexaiProject = userDefaults.string(forKey: "vertexaiProject") ?? ""
972
- self.vertexaiLocation = userDefaults.string(forKey: "vertexaiLocation") ?? ""
973
- self.zaiAPIToken = (try? zaiTokenStore.loadToken()) ?? ""
974
- self.minimaxAPIToken = (try? minimaxTokenStore.loadToken()) ?? ""
975
- self.minimaxCookieHeader = (try? minimaxCookieHeaderStore.loadHeader()) ?? ""
976
- self.minimaxGroupID = (try? minimaxGroupIDStore.loadGroupID()) ?? ""
977
- self.copilotAPIToken = (try? copilotTokenStore.loadToken()) ?? ""
978
- self.openRouterAPIToken = (try? openRouterTokenStore.loadToken()) ?? ""
979
- self.groqAPIToken = (try? groqTokenStore.loadToken()) ?? ""
980
- self.deepSeekAPIToken = (try? deepSeekTokenStore.loadToken()) ?? ""
981
- self.fireworksAPIToken = (try? fireworksTokenStore.loadToken()) ?? ""
982
- self.mistralAPIToken = (try? mistralTokenStore.loadToken()) ?? ""
983
- self.perplexityAPIToken = (try? perplexityTokenStore.loadToken()) ?? ""
984
- self.kimiAPIToken = (try? kimiTokenStore.loadToken()) ?? ""
985
- self.auggieAPIToken = (try? auggieTokenStore.loadToken()) ?? ""
986
- self.togetherAPIToken = (try? togetherTokenStore.loadToken()) ?? ""
987
- self.cohereAPIToken = (try? cohereTokenStore.loadToken()) ?? ""
988
- self.xaiAPIToken = (try? xaiTokenStore.loadToken()) ?? ""
989
- self.cerebrasAPIToken = (try? cerebrasTokenStore.loadToken()) ?? ""
990
- self.sambaNovaAPIToken = (try? sambaNovaTokenStore.loadToken()) ?? ""
991
- self.qwenAPIToken = (try? qwenTokenStore.loadToken()) ?? ""
992
- self.azureOpenAIAPIToken = (try? azureOpenAITokenStore.loadToken()) ?? ""
993
- // Always start on Overview tab.
994
- self.selectedMenuProviderRaw = nil
995
- self.providerDetectionCompleted = userDefaults.object(
996
- forKey: "providerDetectionCompleted") as? Bool ?? false
997
- self.toggleStore = ProviderToggleStore(userDefaults: userDefaults)
998
- self.toggleStore.purgeLegacyKeys()
999
- LaunchAtLoginManager.setEnabled(self.launchAtLogin)
1000
- self.runInitialProviderDetectionIfNeeded()
1001
- self.applyTokenCostDefaultIfNeeded()
1002
- if self.claudeUsageDataSource != .cli {
1003
- self.claudeWebExtrasEnabled = false
1004
- }
1005
- RunicFont.family = self.selectedFontFamily
1006
- }
1007
-
1008
- func orderedProviders() -> [UsageProvider] {
1009
- let raw = self.providerOrderRaw
1010
- if raw == self.cachedProviderOrderRaw, !self.cachedProviderOrder.isEmpty {
1011
- return self.cachedProviderOrder
1012
- }
1013
- let ordered = Self.effectiveProviderOrder(raw: raw)
1014
- self.cachedProviderOrderRaw = raw
1015
- self.cachedProviderOrder = ordered
1016
- return ordered
1017
- }
1018
-
1019
- func moveProvider(fromOffsets: IndexSet, toOffset: Int) {
1020
- var order = self.orderedProviders()
1021
- order.move(fromOffsets: fromOffsets, toOffset: toOffset)
1022
- self.providerOrderRaw = order.map(\.rawValue)
1023
- }
1024
-
1025
- func isProviderEnabled(provider: UsageProvider, metadata: ProviderMetadata) -> Bool {
1026
- _ = self.providerToggleRevision
1027
- return self.toggleStore.isEnabled(metadata: metadata)
1028
- }
1029
-
1030
- func isProviderEnabledCached(
1031
- provider: UsageProvider,
1032
- metadataByProvider: [UsageProvider: ProviderMetadata]) -> Bool
1033
- {
1034
- self.refreshProviderEnablementCacheIfNeeded(metadataByProvider: metadataByProvider)
1035
- return self.cachedProviderEnablement[provider] ?? false
1036
- }
1037
-
1038
- func enabledProvidersOrdered(metadataByProvider: [UsageProvider: ProviderMetadata]) -> [UsageProvider] {
1039
- self.refreshProviderEnablementCacheIfNeeded(metadataByProvider: metadataByProvider)
1040
- let orderRaw = self.providerOrderRaw
1041
- let revision = self.cachedProviderEnablementRevision
1042
- if revision == self.cachedEnabledProvidersRevision,
1043
- orderRaw == self.cachedEnabledProvidersOrderRaw,
1044
- !self.cachedEnabledProviders.isEmpty
1045
- {
1046
- return self.cachedEnabledProviders
1047
- }
1048
- let enabled = self.orderedProviders().filter { self.cachedProviderEnablement[$0] ?? false }
1049
- self.cachedEnabledProviders = enabled
1050
- self.cachedEnabledProvidersRevision = revision
1051
- self.cachedEnabledProvidersOrderRaw = orderRaw
1052
- return enabled
1053
- }
1054
-
1055
- func setProviderEnabled(provider: UsageProvider, metadata: ProviderMetadata, enabled: Bool) {
1056
- self.providerToggleRevision &+= 1
1057
- self.toggleStore.setEnabled(enabled, metadata: metadata)
1058
- }
1059
-
1060
- func rerunProviderDetection() {
1061
- self.runInitialProviderDetectionIfNeeded(force: true)
1062
- }
1063
-
1064
- /// Auto-enable a provider when the user enters a non-empty API token.
1065
- private func autoEnableProviderIfNeeded(cliName: String) {
1066
- let toggles = (self.userDefaults.dictionary(forKey: "providerToggles") as? [String: Bool]) ?? [:]
1067
- guard toggles[cliName] == nil else { return }
1068
- var updated = toggles
1069
- updated[cliName] = true
1070
- self.userDefaults.set(updated, forKey: "providerToggles")
1071
- self.providerToggleRevision &+= 1
1072
- }
1073
-
1074
- // MARK: - Private
1075
-
1076
- func isCostUsageEffectivelyEnabled(for provider: UsageProvider) -> Bool {
1077
- self.costUsageEnabled
1078
- && ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost
1079
- }
1080
-
1081
- private static func effectiveProviderOrder(raw: [String]) -> [UsageProvider] {
1082
- var seen: Set<UsageProvider> = []
1083
- var ordered: [UsageProvider] = []
1084
-
1085
- for rawValue in raw {
1086
- guard let provider = UsageProvider(rawValue: rawValue) else { continue }
1087
- guard !seen.contains(provider) else { continue }
1088
- seen.insert(provider)
1089
- ordered.append(provider)
1090
- }
1091
-
1092
- if ordered.isEmpty {
1093
- ordered = UsageProvider.allCases
1094
- seen = Set(ordered)
1095
- }
1096
-
1097
- if !seen.contains(.factory), let zaiIndex = ordered.firstIndex(of: .zai) {
1098
- ordered.insert(.factory, at: zaiIndex)
1099
- seen.insert(.factory)
1100
- }
1101
-
1102
- for provider in UsageProvider.allCases where !seen.contains(provider) {
1103
- ordered.append(provider)
1104
- }
1105
-
1106
- return ordered
1107
- }
1108
-
1109
- private func refreshProviderEnablementCacheIfNeeded(
1110
- metadataByProvider: [UsageProvider: ProviderMetadata])
1111
- {
1112
- let revision = self.providerToggleRevision
1113
- guard revision != self.cachedProviderEnablementRevision else { return }
1114
- var cache: [UsageProvider: Bool] = [:]
1115
- for (provider, metadata) in metadataByProvider {
1116
- cache[provider] = self.toggleStore.isEnabled(metadata: metadata)
1117
- }
1118
- self.cachedProviderEnablement = cache
1119
- self.cachedProviderEnablementRevision = revision
1120
- }
1121
-
1122
- private func runInitialProviderDetectionIfNeeded(force: Bool = false) {
1123
- guard force || !self.providerDetectionCompleted else { return }
1124
- guard let codexMeta = ProviderRegistry.shared.metadata[.codex],
1125
- let claudeMeta = ProviderRegistry.shared.metadata[.claude],
1126
- let geminiMeta = ProviderRegistry.shared.metadata[.gemini],
1127
- let antigravityMeta = ProviderRegistry.shared.metadata[.antigravity] else { return }
1128
-
1129
- LoginShellPathCache.shared.captureOnce { [weak self] _ in
1130
- Task { @MainActor in
1131
- await self?.applyProviderDetection(
1132
- codexMeta: codexMeta,
1133
- claudeMeta: claudeMeta,
1134
- geminiMeta: geminiMeta,
1135
- antigravityMeta: antigravityMeta)
1136
- }
1137
- }
1138
- }
1139
-
1140
- private func applyProviderDetection(
1141
- codexMeta: ProviderMetadata,
1142
- claudeMeta: ProviderMetadata,
1143
- geminiMeta: ProviderMetadata,
1144
- antigravityMeta: ProviderMetadata) async
1145
- {
1146
- guard !self.providerDetectionCompleted else { return }
1147
- let codexInstalled = BinaryLocator.resolveCodexBinary() != nil
1148
- let claudeInstalled = BinaryLocator.resolveClaudeBinary() != nil
1149
- let geminiInstalled = BinaryLocator.resolveGeminiBinary() != nil
1150
- let antigravityRunning = await AntigravityStatusProbe.isRunning()
1151
-
1152
- // If none installed, keep Codex enabled to match previous behavior.
1153
- let noneInstalled = !codexInstalled && !claudeInstalled && !geminiInstalled && !antigravityRunning
1154
- let enableCodex = codexInstalled || noneInstalled
1155
- let enableClaude = claudeInstalled
1156
- let enableGemini = geminiInstalled
1157
- let enableAntigravity = antigravityRunning
1158
-
1159
- self.providerToggleRevision &+= 1
1160
- self.toggleStore.setEnabled(enableCodex, metadata: codexMeta)
1161
- self.toggleStore.setEnabled(enableClaude, metadata: claudeMeta)
1162
- self.toggleStore.setEnabled(enableGemini, metadata: geminiMeta)
1163
- self.toggleStore.setEnabled(enableAntigravity, metadata: antigravityMeta)
1164
- self.providerDetectionCompleted = true
1165
- }
1166
-
1167
- private func applyTokenCostDefaultIfNeeded() {
1168
- // Settings are persisted in UserDefaults.standard.
1169
- guard UserDefaults.standard.object(forKey: "tokenCostUsageEnabled") == nil else { return }
1170
-
1171
- Task { @MainActor [weak self] in
1172
- guard let self else { return }
1173
- let hasSources = await Task.detached(priority: .utility) {
1174
- Self.hasAnyTokenCostUsageSources()
1175
- }.value
1176
- guard hasSources else { return }
1177
- guard UserDefaults.standard.object(forKey: "tokenCostUsageEnabled") == nil else { return }
1178
- self.costUsageEnabled = true
1179
- }
1180
- }
1181
-
1182
- nonisolated static func hasAnyTokenCostUsageSources(
1183
- env: [String: String] = ProcessInfo.processInfo.environment,
1184
- fileManager: FileManager = .default) -> Bool
1185
- {
1186
- func hasAnyJsonl(in root: URL) -> Bool {
1187
- guard fileManager.fileExists(atPath: root.path) else { return false }
1188
- guard let enumerator = fileManager.enumerator(
1189
- at: root,
1190
- includingPropertiesForKeys: [.isRegularFileKey],
1191
- options: [.skipsHiddenFiles, .skipsPackageDescendants])
1192
- else { return false }
1193
-
1194
- for case let url as URL in enumerator where url.pathExtension.lowercased() == "jsonl" {
1195
- return true
1196
- }
1197
- return false
1198
- }
1199
-
1200
- let codexRoot: URL = {
1201
- let raw = env["CODEX_HOME"]?.trimmingCharacters(in: .whitespacesAndNewlines)
1202
- if let raw, !raw.isEmpty {
1203
- return URL(fileURLWithPath: raw).appendingPathComponent("sessions", isDirectory: true)
1204
- }
1205
- return fileManager.homeDirectoryForCurrentUser
1206
- .appendingPathComponent(".codex", isDirectory: true)
1207
- .appendingPathComponent("sessions", isDirectory: true)
1208
- }()
1209
- if hasAnyJsonl(in: codexRoot) { return true }
1210
-
1211
- let claudeRoots: [URL] = {
1212
- if let env = env["CLAUDE_CONFIG_DIR"]?.trimmingCharacters(in: .whitespacesAndNewlines),
1213
- !env.isEmpty
1214
- {
1215
- return env.split(separator: ",").map { part in
1216
- let raw = String(part).trimmingCharacters(in: .whitespacesAndNewlines)
1217
- let url = URL(fileURLWithPath: raw)
1218
- if url.lastPathComponent == "projects" {
1219
- return url
1220
- }
1221
- return url.appendingPathComponent("projects", isDirectory: true)
1222
- }
1223
- }
1224
-
1225
- let home = fileManager.homeDirectoryForCurrentUser
1226
- return [
1227
- home.appendingPathComponent(".config/claude/projects", isDirectory: true),
1228
- home.appendingPathComponent(".claude/projects", isDirectory: true),
1229
- ]
1230
- }()
1231
-
1232
- return claudeRoots.contains(where: hasAnyJsonl(in:))
1233
- }
1234
-
1235
- private func schedulePersistZaiAPIToken() {
1236
- self.zaiTokenPersistTask?.cancel()
1237
- let token = self.zaiAPIToken
1238
- let tokenStore = self.zaiTokenStore
1239
- self.zaiTokenPersistTask = Task { @MainActor in
1240
- do {
1241
- try await Task.sleep(nanoseconds: 350_000_000)
1242
- } catch {
1243
- return
1244
- }
1245
- guard !Task.isCancelled else { return }
1246
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1247
- do {
1248
- try tokenStore.storeToken(token)
1249
- return nil
1250
- } catch {
1251
- return error
1252
- }
1253
- }.value
1254
- if let error {
1255
- // Keep value in memory; persist best-effort.
1256
- RunicLog.logger("zai-token-store").error("Failed to persist z.ai token: \(error)")
1257
- }
1258
- }
1259
- }
1260
-
1261
- private func schedulePersistMiniMaxAPIToken() {
1262
- self.minimaxTokenPersistTask?.cancel()
1263
- let token = self.minimaxAPIToken
1264
- let tokenStore = self.minimaxTokenStore
1265
- self.minimaxTokenPersistTask = Task { @MainActor in
1266
- do {
1267
- try await Task.sleep(nanoseconds: 350_000_000)
1268
- } catch {
1269
- return
1270
- }
1271
- guard !Task.isCancelled else { return }
1272
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1273
- do {
1274
- try tokenStore.storeToken(token)
1275
- return nil
1276
- } catch {
1277
- return error
1278
- }
1279
- }.value
1280
- if let error {
1281
- RunicLog.logger("minimax-token-store").error("Failed to persist MiniMax token: \(error)")
1282
- }
1283
- }
1284
- }
1285
-
1286
- private func schedulePersistMiniMaxCookieHeader() {
1287
- self.minimaxCookieHeaderPersistTask?.cancel()
1288
- let header = self.minimaxCookieHeader
1289
- let store = self.minimaxCookieHeaderStore
1290
- self.minimaxCookieHeaderPersistTask = Task { @MainActor in
1291
- do {
1292
- try await Task.sleep(nanoseconds: 350_000_000)
1293
- } catch {
1294
- return
1295
- }
1296
- guard !Task.isCancelled else { return }
1297
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1298
- do {
1299
- try store.storeHeader(header)
1300
- return nil
1301
- } catch {
1302
- return error
1303
- }
1304
- }.value
1305
- if let error {
1306
- RunicLog.logger("minimax-cookie-store").error("Failed to persist MiniMax cookie header: \(error)")
1307
- }
1308
- }
1309
- }
1310
-
1311
- private func schedulePersistMiniMaxGroupID() {
1312
- self.minimaxGroupIDPersistTask?.cancel()
1313
- let groupID = self.minimaxGroupID
1314
- let groupStore = self.minimaxGroupIDStore
1315
- self.minimaxGroupIDPersistTask = Task { @MainActor in
1316
- do {
1317
- try await Task.sleep(nanoseconds: 350_000_000)
1318
- } catch {
1319
- return
1320
- }
1321
- guard !Task.isCancelled else { return }
1322
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1323
- do {
1324
- try groupStore.storeGroupID(groupID)
1325
- return nil
1326
- } catch {
1327
- return error
1328
- }
1329
- }.value
1330
- if let error {
1331
- RunicLog.logger("minimax-groupid-store").error("Failed to persist MiniMax Group ID: \(error)")
1332
- }
1333
- }
1334
- }
1335
-
1336
- private func schedulePersistCopilotAPIToken() {
1337
- self.copilotTokenPersistTask?.cancel()
1338
- let token = self.copilotAPIToken
1339
- let tokenStore = self.copilotTokenStore
1340
- self.copilotTokenPersistTask = Task { @MainActor in
1341
- do {
1342
- try await Task.sleep(nanoseconds: 350_000_000)
1343
- } catch {
1344
- return
1345
- }
1346
- guard !Task.isCancelled else { return }
1347
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1348
- do {
1349
- try tokenStore.storeToken(token)
1350
- return nil
1351
- } catch {
1352
- return error
1353
- }
1354
- }.value
1355
- if let error {
1356
- RunicLog.logger("copilot-token-store").error("Failed to persist Copilot token: \(error)")
1357
- }
1358
- }
1359
- }
1360
-
1361
- private func schedulePersistOpenRouterAPIToken() {
1362
- self.openRouterTokenPersistTask?.cancel()
1363
- let token = self.openRouterAPIToken
1364
- let tokenStore = self.openRouterTokenStore
1365
- self.openRouterTokenPersistTask = Task { @MainActor in
1366
- do {
1367
- try await Task.sleep(nanoseconds: 350_000_000)
1368
- } catch {
1369
- return
1370
- }
1371
- guard !Task.isCancelled else { return }
1372
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1373
- do {
1374
- try tokenStore.storeToken(token)
1375
- return nil
1376
- } catch {
1377
- return error
1378
- }
1379
- }.value
1380
- if let error {
1381
- RunicLog.logger("openrouter-token-store").error("Failed to persist OpenRouter token: \(error)")
1382
- }
1383
- }
1384
- }
1385
-
1386
- private func schedulePersistGroqAPIToken() {
1387
- self.groqTokenPersistTask?.cancel()
1388
- let token = self.groqAPIToken
1389
- let tokenStore = self.groqTokenStore
1390
- self.groqTokenPersistTask = Task { @MainActor in
1391
- do {
1392
- try await Task.sleep(nanoseconds: 350_000_000)
1393
- } catch {
1394
- return
1395
- }
1396
- guard !Task.isCancelled else { return }
1397
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1398
- do {
1399
- try tokenStore.storeToken(token)
1400
- return nil
1401
- } catch {
1402
- return error
1403
- }
1404
- }.value
1405
- if let error {
1406
- RunicLog.logger("groq-token-store").error("Failed to persist Groq token: \(error)")
1407
- }
1408
- }
1409
- }
1410
-
1411
- private func schedulePersistDeepSeekAPIToken() {
1412
- self.deepSeekTokenPersistTask?.cancel()
1413
- let token = self.deepSeekAPIToken
1414
- let tokenStore = self.deepSeekTokenStore
1415
- self.deepSeekTokenPersistTask = Task { @MainActor in
1416
- do {
1417
- try await Task.sleep(nanoseconds: 350_000_000)
1418
- } catch {
1419
- return
1420
- }
1421
- guard !Task.isCancelled else { return }
1422
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1423
- do {
1424
- try tokenStore.storeToken(token)
1425
- return nil
1426
- } catch {
1427
- return error
1428
- }
1429
- }.value
1430
- if let error {
1431
- RunicLog.logger("deepseek-token-store").error("Failed to persist DeepSeek token: \(error)")
1432
- }
1433
- }
1434
- }
1435
-
1436
- private func schedulePersistFireworksAPIToken() {
1437
- self.fireworksTokenPersistTask?.cancel()
1438
- let token = self.fireworksAPIToken
1439
- let tokenStore = self.fireworksTokenStore
1440
- self.fireworksTokenPersistTask = Task { @MainActor in
1441
- do {
1442
- try await Task.sleep(nanoseconds: 350_000_000)
1443
- } catch {
1444
- return
1445
- }
1446
- guard !Task.isCancelled else { return }
1447
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1448
- do {
1449
- try tokenStore.storeToken(token)
1450
- return nil
1451
- } catch {
1452
- return error
1453
- }
1454
- }.value
1455
- if let error {
1456
- RunicLog.logger("fireworks-token-store").error("Failed to persist Fireworks token: \(error)")
1457
- }
1458
- }
1459
- }
1460
-
1461
- private func schedulePersistMistralAPIToken() {
1462
- self.mistralTokenPersistTask?.cancel()
1463
- let token = self.mistralAPIToken
1464
- let tokenStore = self.mistralTokenStore
1465
- self.mistralTokenPersistTask = Task { @MainActor in
1466
- do {
1467
- try await Task.sleep(nanoseconds: 350_000_000)
1468
- } catch {
1469
- return
1470
- }
1471
- guard !Task.isCancelled else { return }
1472
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1473
- do {
1474
- try tokenStore.storeToken(token)
1475
- return nil
1476
- } catch {
1477
- return error
1478
- }
1479
- }.value
1480
- if let error {
1481
- RunicLog.logger("mistral-token-store").error("Failed to persist Mistral token: \(error)")
1482
- }
1483
- }
1484
- }
1485
-
1486
- private func schedulePersistPerplexityAPIToken() {
1487
- self.perplexityTokenPersistTask?.cancel()
1488
- let token = self.perplexityAPIToken
1489
- let tokenStore = self.perplexityTokenStore
1490
- self.perplexityTokenPersistTask = Task { @MainActor in
1491
- do {
1492
- try await Task.sleep(nanoseconds: 350_000_000)
1493
- } catch {
1494
- return
1495
- }
1496
- guard !Task.isCancelled else { return }
1497
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1498
- do {
1499
- try tokenStore.storeToken(token)
1500
- return nil
1501
- } catch {
1502
- return error
1503
- }
1504
- }.value
1505
- if let error {
1506
- RunicLog.logger("perplexity-token-store").error("Failed to persist Perplexity token: \(error)")
1507
- }
1508
- }
1509
- }
1510
-
1511
- private func schedulePersistKimiAPIToken() {
1512
- self.kimiTokenPersistTask?.cancel()
1513
- let token = self.kimiAPIToken
1514
- let tokenStore = self.kimiTokenStore
1515
- self.kimiTokenPersistTask = Task { @MainActor in
1516
- do {
1517
- try await Task.sleep(nanoseconds: 350_000_000)
1518
- } catch {
1519
- return
1520
- }
1521
- guard !Task.isCancelled else { return }
1522
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1523
- do {
1524
- try tokenStore.storeToken(token)
1525
- return nil
1526
- } catch {
1527
- return error
1528
- }
1529
- }.value
1530
- if let error {
1531
- RunicLog.logger("kimi-token-store").error("Failed to persist Kimi token: \(error)")
1532
- }
1533
- }
1534
- }
1535
-
1536
- private func schedulePersistAuggieAPIToken() {
1537
- self.auggieTokenPersistTask?.cancel()
1538
- let token = self.auggieAPIToken
1539
- let tokenStore = self.auggieTokenStore
1540
- self.auggieTokenPersistTask = Task { @MainActor in
1541
- do {
1542
- try await Task.sleep(nanoseconds: 350_000_000)
1543
- } catch {
1544
- return
1545
- }
1546
- guard !Task.isCancelled else { return }
1547
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1548
- do {
1549
- try tokenStore.storeToken(token)
1550
- return nil
1551
- } catch {
1552
- return error
1553
- }
1554
- }.value
1555
- if let error {
1556
- RunicLog.logger("auggie-token-store").error("Failed to persist Auggie token: \(error)")
1557
- }
1558
- }
1559
- }
1560
-
1561
- private func schedulePersistTogetherAPIToken() {
1562
- self.togetherTokenPersistTask?.cancel()
1563
- let token = self.togetherAPIToken
1564
- let tokenStore = self.togetherTokenStore
1565
- self.togetherTokenPersistTask = Task { @MainActor in
1566
- do {
1567
- try await Task.sleep(nanoseconds: 350_000_000)
1568
- } catch {
1569
- return
1570
- }
1571
- guard !Task.isCancelled else { return }
1572
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1573
- do {
1574
- try tokenStore.storeToken(token)
1575
- return nil
1576
- } catch {
1577
- return error
1578
- }
1579
- }.value
1580
- if let error {
1581
- RunicLog.logger("together-token-store").error("Failed to persist Together token: \(error)")
1582
- }
1583
- }
1584
- }
1585
-
1586
- private func schedulePersistCohereAPIToken() {
1587
- self.cohereTokenPersistTask?.cancel()
1588
- let token = self.cohereAPIToken
1589
- let tokenStore = self.cohereTokenStore
1590
- self.cohereTokenPersistTask = Task { @MainActor in
1591
- do {
1592
- try await Task.sleep(nanoseconds: 350_000_000)
1593
- } catch {
1594
- return
1595
- }
1596
- guard !Task.isCancelled else { return }
1597
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1598
- do {
1599
- try tokenStore.storeToken(token)
1600
- return nil
1601
- } catch {
1602
- return error
1603
- }
1604
- }.value
1605
- if let error {
1606
- RunicLog.logger("cohere-token-store").error("Failed to persist Cohere token: \(error)")
1607
- }
1608
- }
1609
- }
1610
-
1611
- private func schedulePersistXAiAPIToken() {
1612
- self.xaiTokenPersistTask?.cancel()
1613
- let token = self.xaiAPIToken
1614
- let tokenStore = self.xaiTokenStore
1615
- self.xaiTokenPersistTask = Task { @MainActor in
1616
- do {
1617
- try await Task.sleep(nanoseconds: 350_000_000)
1618
- } catch {
1619
- return
1620
- }
1621
- guard !Task.isCancelled else { return }
1622
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1623
- do {
1624
- try tokenStore.storeToken(token)
1625
- return nil
1626
- } catch {
1627
- return error
1628
- }
1629
- }.value
1630
- if let error {
1631
- RunicLog.logger("xai-token-store").error("Failed to persist xAI token: \(error)")
1632
- }
1633
- }
1634
- }
1635
-
1636
- private func schedulePersistCerebrasAPIToken() {
1637
- self.cerebrasTokenPersistTask?.cancel()
1638
- let token = self.cerebrasAPIToken
1639
- let tokenStore = self.cerebrasTokenStore
1640
- self.cerebrasTokenPersistTask = Task { @MainActor in
1641
- do {
1642
- try await Task.sleep(nanoseconds: 350_000_000)
1643
- } catch {
1644
- return
1645
- }
1646
- guard !Task.isCancelled else { return }
1647
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1648
- do {
1649
- try tokenStore.storeToken(token)
1650
- return nil
1651
- } catch {
1652
- return error
1653
- }
1654
- }.value
1655
- if let error {
1656
- RunicLog.logger("cerebras-token-store").error("Failed to persist Cerebras token: \(error)")
1657
- }
1658
- }
1659
- }
1660
-
1661
- private func schedulePersistSambaNovaAPIToken() {
1662
- self.sambaNovaTokenPersistTask?.cancel()
1663
- let token = self.sambaNovaAPIToken
1664
- let tokenStore = self.sambaNovaTokenStore
1665
- self.sambaNovaTokenPersistTask = Task { @MainActor in
1666
- do {
1667
- try await Task.sleep(nanoseconds: 350_000_000)
1668
- } catch {
1669
- return
1670
- }
1671
- guard !Task.isCancelled else { return }
1672
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1673
- do {
1674
- try tokenStore.storeToken(token)
1675
- return nil
1676
- } catch {
1677
- return error
1678
- }
1679
- }.value
1680
- if let error {
1681
- RunicLog.logger("sambanova-token-store").error("Failed to persist SambaNova token: \(error)")
1682
- }
1683
- }
1684
- }
1685
-
1686
- private func schedulePersistAzureOpenAIAPIToken() {
1687
- self.azureOpenAITokenPersistTask?.cancel()
1688
- let token = self.azureOpenAIAPIToken
1689
- let tokenStore = self.azureOpenAITokenStore
1690
- self.azureOpenAITokenPersistTask = Task { @MainActor in
1691
- do {
1692
- try await Task.sleep(nanoseconds: 350_000_000)
1693
- } catch {
1694
- return
1695
- }
1696
- guard !Task.isCancelled else { return }
1697
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1698
- do {
1699
- try tokenStore.storeToken(token)
1700
- return nil
1701
- } catch {
1702
- return error
1703
- }
1704
- }.value
1705
- if let error {
1706
- RunicLog.logger("azure-openai-token-store")
1707
- .error("Failed to persist Azure OpenAI token: \(error)")
1708
- }
1709
- }
1710
- }
1711
-
1712
- private func schedulePersistQwenAPIToken() {
1713
- self.qwenTokenPersistTask?.cancel()
1714
- let token = self.qwenAPIToken
1715
- let tokenStore = self.qwenTokenStore
1716
- self.qwenTokenPersistTask = Task { @MainActor in
1717
- do {
1718
- try await Task.sleep(nanoseconds: 350_000_000)
1719
- } catch {
1720
- return
1721
- }
1722
- guard !Task.isCancelled else { return }
1723
- let error: (any Error)? = await Task.detached(priority: .utility) { () -> (any Error)? in
1724
- do {
1725
- try tokenStore.storeToken(token)
1726
- return nil
1727
- } catch {
1728
- return error
1729
- }
1730
- }.value
1731
- if let error {
1732
- RunicLog.logger("qwen-token-store").error("Failed to persist Qwen token: \(error)")
1733
- }
1734
- }
1735
- }
1736
- }
1737
-
1738
- enum LaunchAtLoginManager {
1739
- @MainActor
1740
- static func setEnabled(_ enabled: Bool) {
1741
- guard #available(macOS 13, *) else { return }
1742
- let service = SMAppService.mainApp
1743
- if enabled {
1744
- try? service.register()
1745
- } else {
1746
- try? service.unregister()
1747
- }
1748
- }
1749
- }