@sriinnu/runic 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (584) hide show
  1. package/.swiftformat +50 -0
  2. package/.swiftlint.yml +160 -0
  3. package/CHANGELOG.md +307 -0
  4. package/CONTRIBUTING.md +456 -0
  5. package/Icon.icns +0 -0
  6. package/Icon.icon/Assets/runic.png +0 -0
  7. package/Icon.icon/icon.json +36 -0
  8. package/LICENSE +21 -0
  9. package/Package.resolved +51 -0
  10. package/Package.swift +136 -0
  11. package/Packages/Helix/LICENSE +21 -0
  12. package/Packages/Helix/Package.swift +29 -0
  13. package/Packages/Helix/README.md +976 -0
  14. package/Packages/Helix/Sources/Helix/Binding.swift +111 -0
  15. package/Packages/Helix/Sources/Helix/CommandParser.swift +160 -0
  16. package/Packages/Helix/Sources/Helix/CommandSignature.swift +117 -0
  17. package/Packages/Helix/Sources/Helix/ExpressibleFromArgument.swift +72 -0
  18. package/Packages/Helix/Sources/Helix/HelpGenerator.swift +175 -0
  19. package/Packages/Helix/Sources/Helix/NameSpecification.swift +98 -0
  20. package/Packages/Helix/Sources/Helix/ParsableCommand.swift +204 -0
  21. package/Packages/Helix/Sources/Helix/Platform/DarwinPlatformContext.swift +44 -0
  22. package/Packages/Helix/Sources/Helix/Platform/LinuxPlatformContext.swift +34 -0
  23. package/Packages/Helix/Sources/Helix/Platform/PlatformContext+Default.swift +91 -0
  24. package/Packages/Helix/Sources/Helix/Platform/PlatformContext.swift +94 -0
  25. package/Packages/Helix/Sources/Helix/Platform/PlatformPath.swift +167 -0
  26. package/Packages/Helix/Sources/Helix/Platform/Stdio.swift +99 -0
  27. package/Packages/Helix/Sources/Helix/Platform/WebPlatformContext.swift +146 -0
  28. package/Packages/Helix/Sources/Helix/Platform/WindowsPlatformContext.swift +97 -0
  29. package/Packages/Helix/Sources/Helix/Program.swift +204 -0
  30. package/Packages/Helix/Sources/Helix/PropertyWrappers.swift +367 -0
  31. package/Packages/Silo/LICENSE +21 -0
  32. package/Packages/Silo/Package.swift +34 -0
  33. package/Packages/Silo/README.md +466 -0
  34. package/Packages/Silo/Sources/Silo/BinaryCookiesReader.swift +169 -0
  35. package/Packages/Silo/Sources/Silo/BrowserCookieAnalytics.swift +365 -0
  36. package/Packages/Silo/Sources/Silo/BrowserCookieBackends.swift +594 -0
  37. package/Packages/Silo/Sources/Silo/BrowserCookieClient.swift +326 -0
  38. package/Packages/Silo/Sources/Silo/BrowserCookieExport.swift +154 -0
  39. package/Packages/Silo/Sources/Silo/BrowserCookieImport.swift +119 -0
  40. package/Packages/Silo/Sources/Silo/BrowserCookieMockStore.swift +121 -0
  41. package/Packages/Silo/Sources/Silo/BrowserCookieModels.swift +391 -0
  42. package/Packages/Silo/Sources/Silo/ChromiumCookieReader.swift +240 -0
  43. package/Packages/Silo/Sources/Silo/CryptoSupport.swift +86 -0
  44. package/Packages/Silo/Sources/Silo/FirefoxCookieReader.swift +172 -0
  45. package/Packages/Silo/Sources/Silo/LinuxChromiumCookieReader.swift +172 -0
  46. package/Packages/Silo/Sources/Silo/LinuxSecretService.swift +105 -0
  47. package/Packages/Silo/Sources/Silo/MacOSChromiumCookieReader.swift +191 -0
  48. package/Packages/Silo/Sources/Silo/SQLiteSnapshot.swift +41 -0
  49. package/Packages/Silo/Sources/Silo/WindowsChromiumCookieReader.swift +110 -0
  50. package/README.md +109 -0
  51. package/RuniciOS/App/RuniciOSApp.swift +105 -0
  52. package/RuniciOS/Core/iOSUsageStore.swift +192 -0
  53. package/RuniciOS/Views/ProviderDetailView.swift +312 -0
  54. package/RuniciOS/Views/ProviderListView.swift +228 -0
  55. package/RuniciOS/Widgets/LargeWidget.swift +367 -0
  56. package/RuniciOS/Widgets/LiveActivity.swift +342 -0
  57. package/RuniciOS/Widgets/LockScreenWidget.swift +273 -0
  58. package/RuniciOS/Widgets/MediumWidget.swift +370 -0
  59. package/RuniciOS/Widgets/RunicWidget.swift +274 -0
  60. package/RuniciOS/Widgets/SmallWidget.swift +281 -0
  61. package/RuniciOS/Widgets/WidgetModels.swift +285 -0
  62. package/RuniciOS/Widgets/WidgetTimeline.swift +270 -0
  63. package/Scripts/CREATION-SUMMARY.md +367 -0
  64. package/Scripts/DIRECTORY-STRUCTURE.md +358 -0
  65. package/Scripts/GETTING-STARTED-CHECKLIST.md +364 -0
  66. package/Scripts/INDEX.md +365 -0
  67. package/Scripts/QUICK-REFERENCE.md +164 -0
  68. package/Scripts/README-SCRIPTS.md +926 -0
  69. package/Scripts/build-android.sh +526 -0
  70. package/Scripts/build-ios.sh +529 -0
  71. package/Scripts/build-macos.sh +603 -0
  72. package/Scripts/build-windows.sh +504 -0
  73. package/Scripts/build_icon.sh +49 -0
  74. package/Scripts/changelog-to-html.sh +89 -0
  75. package/Scripts/check-release-assets.sh +10 -0
  76. package/Scripts/ci-config.yml +474 -0
  77. package/Scripts/compile_and_run.sh +219 -0
  78. package/Scripts/compile_and_run_adhoc.sh +4 -0
  79. package/Scripts/docs-list.mjs +119 -0
  80. package/Scripts/make_appcast.sh +58 -0
  81. package/Scripts/package_app.sh +409 -0
  82. package/Scripts/release-lib.sh +214 -0
  83. package/Scripts/release.sh +76 -0
  84. package/Scripts/setup-all.sh +387 -0
  85. package/Scripts/setup-ios.sh +404 -0
  86. package/Scripts/setup-react-native.sh +523 -0
  87. package/Scripts/sign-and-notarize.sh +122 -0
  88. package/Scripts/test_live_update.sh +38 -0
  89. package/Scripts/validate_changelog.sh +23 -0
  90. package/Scripts/verify_appcast.sh +92 -0
  91. package/Sources/Runic/About.swift +93 -0
  92. package/Sources/Runic/AppNotifications.swift +115 -0
  93. package/Sources/Runic/Controllers/StatusItemController+Actions.swift +657 -0
  94. package/Sources/Runic/Controllers/StatusItemController+Animation.swift +518 -0
  95. package/Sources/Runic/Controllers/StatusItemController+ChartSubmenus.swift +810 -0
  96. package/Sources/Runic/Controllers/StatusItemController+CustomProviders.swift +87 -0
  97. package/Sources/Runic/Controllers/StatusItemController+Menu.swift +1379 -0
  98. package/Sources/Runic/Controllers/StatusItemController+MenuCards.swift +337 -0
  99. package/Sources/Runic/Controllers/StatusItemController+MenuHelpers.swift +395 -0
  100. package/Sources/Runic/Controllers/StatusItemController.swift +360 -0
  101. package/Sources/Runic/Core/BudgetNotificationManager.swift +80 -0
  102. package/Sources/Runic/Core/Login/ClaudeLoginRunner.swift +103 -0
  103. package/Sources/Runic/Core/Login/CodexLoginRunner.swift +154 -0
  104. package/Sources/Runic/Core/Login/CursorLoginRunner.swift +206 -0
  105. package/Sources/Runic/Core/Login/GeminiLoginRunner.swift +95 -0
  106. package/Sources/Runic/Core/Rendering/IconRenderer.swift +1216 -0
  107. package/Sources/Runic/Core/Rendering/IconView.swift +120 -0
  108. package/Sources/Runic/Core/Rendering/ProviderBrandIcon.swift +71 -0
  109. package/Sources/Runic/Core/RunicAnimation.swift +53 -0
  110. package/Sources/Runic/Core/RunicColors.swift +73 -0
  111. package/Sources/Runic/Core/RunicCornerRadius.swift +15 -0
  112. package/Sources/Runic/Core/RunicSpacing.swift +68 -0
  113. package/Sources/Runic/Core/Stores/AuggieTokenStore.swift +143 -0
  114. package/Sources/Runic/Core/Stores/AzureOpenAITokenStore.swift +143 -0
  115. package/Sources/Runic/Core/Stores/CerebrasTokenStore.swift +143 -0
  116. package/Sources/Runic/Core/Stores/CohereTokenStore.swift +143 -0
  117. package/Sources/Runic/Core/Stores/CopilotTokenStore.swift +143 -0
  118. package/Sources/Runic/Core/Stores/CustomProviderStore.swift +158 -0
  119. package/Sources/Runic/Core/Stores/DeepSeekTokenStore.swift +143 -0
  120. package/Sources/Runic/Core/Stores/FireworksTokenStore.swift +143 -0
  121. package/Sources/Runic/Core/Stores/GroqTokenStore.swift +143 -0
  122. package/Sources/Runic/Core/Stores/KimiTokenStore.swift +143 -0
  123. package/Sources/Runic/Core/Stores/MiniMaxCookieHeaderStore.swift +143 -0
  124. package/Sources/Runic/Core/Stores/MiniMaxGroupIDStore.swift +143 -0
  125. package/Sources/Runic/Core/Stores/MiniMaxTokenStore.swift +143 -0
  126. package/Sources/Runic/Core/Stores/MistralTokenStore.swift +143 -0
  127. package/Sources/Runic/Core/Stores/OpenRouterTokenStore.swift +143 -0
  128. package/Sources/Runic/Core/Stores/PerplexityTokenStore.swift +143 -0
  129. package/Sources/Runic/Core/Stores/ProviderToggleStore.swift +30 -0
  130. package/Sources/Runic/Core/Stores/QwenTokenStore.swift +143 -0
  131. package/Sources/Runic/Core/Stores/SambaNovaTokenStore.swift +143 -0
  132. package/Sources/Runic/Core/Stores/SettingsStore.swift +1702 -0
  133. package/Sources/Runic/Core/Stores/TogetherTokenStore.swift +143 -0
  134. package/Sources/Runic/Core/Stores/UsageStore+Accessors.swift +20 -0
  135. package/Sources/Runic/Core/Stores/UsageStore+Status.swift +189 -0
  136. package/Sources/Runic/Core/Stores/UsageStore+TokenCost.swift +33 -0
  137. package/Sources/Runic/Core/Stores/UsageStore+WidgetSnapshot.swift +67 -0
  138. package/Sources/Runic/Core/Stores/UsageStore.swift +3564 -0
  139. package/Sources/Runic/Core/Stores/XAITokenStore.swift +143 -0
  140. package/Sources/Runic/Core/Stores/ZaiTokenStore.swift +143 -0
  141. package/Sources/Runic/Core/UsageExporter.swift +193 -0
  142. package/Sources/Runic/Date+RelativeDescription.swift +21 -0
  143. package/Sources/Runic/HiddenWindowView.swift +32 -0
  144. package/Sources/Runic/InstallOrigin.swift +9 -0
  145. package/Sources/Runic/KeyboardShortcuts+Names.swift +6 -0
  146. package/Sources/Runic/MouseLocationReader.swift +65 -0
  147. package/Sources/Runic/Notifications+Runic.swift +6 -0
  148. package/Sources/Runic/OpenAICreditsPurchaseWindowController.swift +503 -0
  149. package/Sources/Runic/ProviderRegistry.swift +100 -0
  150. package/Sources/Runic/ProviderSwitcherButtons.swift +267 -0
  151. package/Sources/Runic/Providers/Antigravity/AntigravityLoginFlow.swift +11 -0
  152. package/Sources/Runic/Providers/Antigravity/AntigravityProviderImplementation.swift +14 -0
  153. package/Sources/Runic/Providers/Auggie/AuggieProviderImplementation.swift +24 -0
  154. package/Sources/Runic/Providers/Azure/AzureProviderImplementation.swift +52 -0
  155. package/Sources/Runic/Providers/Bedrock/BedrockProviderImplementation.swift +42 -0
  156. package/Sources/Runic/Providers/Cerebras/CerebrasProviderImplementation.swift +24 -0
  157. package/Sources/Runic/Providers/Claude/ClaudeLoginFlow.swift +26 -0
  158. package/Sources/Runic/Providers/Claude/ClaudeProviderImplementation.swift +14 -0
  159. package/Sources/Runic/Providers/Codex/CodexLoginFlow.swift +18 -0
  160. package/Sources/Runic/Providers/Codex/CodexProviderImplementation.swift +15 -0
  161. package/Sources/Runic/Providers/Cohere/CohereProviderImplementation.swift +24 -0
  162. package/Sources/Runic/Providers/Copilot/CopilotLoginFlow.swift +193 -0
  163. package/Sources/Runic/Providers/Copilot/CopilotProviderImplementation.swift +110 -0
  164. package/Sources/Runic/Providers/Cursor/CursorLoginFlow.swift +28 -0
  165. package/Sources/Runic/Providers/Cursor/CursorProviderImplementation.swift +15 -0
  166. package/Sources/Runic/Providers/DeepSeek/DeepSeekProviderImplementation.swift +24 -0
  167. package/Sources/Runic/Providers/Factory/FactoryLoginFlow.swift +12 -0
  168. package/Sources/Runic/Providers/Factory/FactoryProviderImplementation.swift +15 -0
  169. package/Sources/Runic/Providers/Fireworks/FireworksProviderImplementation.swift +24 -0
  170. package/Sources/Runic/Providers/Gemini/GeminiLoginFlow.swift +20 -0
  171. package/Sources/Runic/Providers/Gemini/GeminiProviderImplementation.swift +15 -0
  172. package/Sources/Runic/Providers/Groq/GroqProviderImplementation.swift +24 -0
  173. package/Sources/Runic/Providers/Kimi/KimiProviderImplementation.swift +24 -0
  174. package/Sources/Runic/Providers/MiniMax/MiniMaxProviderImplementation.swift +32 -0
  175. package/Sources/Runic/Providers/Mistral/MistralProviderImplementation.swift +24 -0
  176. package/Sources/Runic/Providers/OpenRouter/OpenRouterProviderImplementation.swift +24 -0
  177. package/Sources/Runic/Providers/Perplexity/PerplexityProviderImplementation.swift +24 -0
  178. package/Sources/Runic/Providers/SambaNova/SambaNovaProviderImplementation.swift +24 -0
  179. package/Sources/Runic/Providers/Shared/ProviderCatalog.swift +15 -0
  180. package/Sources/Runic/Providers/Shared/ProviderImplementation.swift +48 -0
  181. package/Sources/Runic/Providers/Shared/ProviderImplementationRegistry.swift +66 -0
  182. package/Sources/Runic/Providers/Shared/ProviderLoginFlow.swift +12 -0
  183. package/Sources/Runic/Providers/Shared/ProviderSettingsDescriptors.swift +99 -0
  184. package/Sources/Runic/Providers/Shared/SystemSettingsLinks.swift +18 -0
  185. package/Sources/Runic/Providers/Together/TogetherProviderImplementation.swift +24 -0
  186. package/Sources/Runic/Providers/XAI/XAIProviderImplementation.swift +24 -0
  187. package/Sources/Runic/Providers/Zai/ZaiProviderImplementation.swift +24 -0
  188. package/Sources/Runic/Resources/ProviderIcon-antigravity.svg +2 -0
  189. package/Sources/Runic/Resources/ProviderIcon-auggie.svg +3 -0
  190. package/Sources/Runic/Resources/ProviderIcon-azure.svg +5 -0
  191. package/Sources/Runic/Resources/ProviderIcon-bedrock.svg +7 -0
  192. package/Sources/Runic/Resources/ProviderIcon-cerebras.svg +3 -0
  193. package/Sources/Runic/Resources/ProviderIcon-claude.svg +1 -0
  194. package/Sources/Runic/Resources/ProviderIcon-codex.svg +1 -0
  195. package/Sources/Runic/Resources/ProviderIcon-cohere.svg +3 -0
  196. package/Sources/Runic/Resources/ProviderIcon-copilot.svg +1 -0
  197. package/Sources/Runic/Resources/ProviderIcon-cursor.svg +3 -0
  198. package/Sources/Runic/Resources/ProviderIcon-deepseek.svg +4 -0
  199. package/Sources/Runic/Resources/ProviderIcon-factory.svg +3 -0
  200. package/Sources/Runic/Resources/ProviderIcon-fireworks.svg +3 -0
  201. package/Sources/Runic/Resources/ProviderIcon-gemini.svg +1 -0
  202. package/Sources/Runic/Resources/ProviderIcon-groq.svg +1 -0
  203. package/Sources/Runic/Resources/ProviderIcon-kimi.svg +4 -0
  204. package/Sources/Runic/Resources/ProviderIcon-minimax.svg +1 -0
  205. package/Sources/Runic/Resources/ProviderIcon-mistral.svg +5 -0
  206. package/Sources/Runic/Resources/ProviderIcon-openrouter.svg +7 -0
  207. package/Sources/Runic/Resources/ProviderIcon-perplexity.svg +4 -0
  208. package/Sources/Runic/Resources/ProviderIcon-qwen.svg +9 -0
  209. package/Sources/Runic/Resources/ProviderIcon-sambanova.svg +4 -0
  210. package/Sources/Runic/Resources/ProviderIcon-together.svg +5 -0
  211. package/Sources/Runic/Resources/ProviderIcon-vertexai.svg +17 -0
  212. package/Sources/Runic/Resources/ProviderIcon-xai.svg +3 -0
  213. package/Sources/Runic/Resources/ProviderIcon-zai.svg +5 -0
  214. package/Sources/Runic/Resources/RunicMenubarIcon.svg +7 -0
  215. package/Sources/Runic/RunicApp.swift +357 -0
  216. package/Sources/Runic/SessionQuotaNotifications.swift +58 -0
  217. package/Sources/Runic/UsagePaceText.swift +52 -0
  218. package/Sources/Runic/UsageProgressBar.swift +224 -0
  219. package/Sources/Runic/Utilities/DisplayLink.swift +96 -0
  220. package/Sources/Runic/Utilities/LoadingPattern.swift +60 -0
  221. package/Sources/Runic/Utilities/PerformanceConstants.swift +85 -0
  222. package/Sources/Runic/Views/Menu/AlertsMenuView.swift +256 -0
  223. package/Sources/Runic/Views/Menu/ChartPanelStyle.swift +22 -0
  224. package/Sources/Runic/Views/Menu/CostComparativeChartMenuView.swift +275 -0
  225. package/Sources/Runic/Views/Menu/CostHistoryChartMenuView.swift +377 -0
  226. package/Sources/Runic/Views/Menu/CreditsHistoryChartMenuView.swift +312 -0
  227. package/Sources/Runic/Views/Menu/EfficiencyMetricsMenuView.swift +312 -0
  228. package/Sources/Runic/Views/Menu/HeroStatCardsMenuView.swift +228 -0
  229. package/Sources/Runic/Views/Menu/HourlyActivityChartMenuView.swift +228 -0
  230. package/Sources/Runic/Views/Menu/InlineUsageChartView.swift +162 -0
  231. package/Sources/Runic/Views/Menu/MenuCardEntranceModifier.swift +64 -0
  232. package/Sources/Runic/Views/Menu/MenuCardSidebarView.swift +268 -0
  233. package/Sources/Runic/Views/Menu/MenuCardSkeletonView.swift +104 -0
  234. package/Sources/Runic/Views/Menu/MenuCardView.swift +1900 -0
  235. package/Sources/Runic/Views/Menu/MenuContent.swift +150 -0
  236. package/Sources/Runic/Views/Menu/MenuDescriptor.swift +369 -0
  237. package/Sources/Runic/Views/Menu/MenuHighlightStyle.swift +42 -0
  238. package/Sources/Runic/Views/Menu/ModelBreakdownMenuView.swift +235 -0
  239. package/Sources/Runic/Views/Menu/OverviewMenuView.swift +141 -0
  240. package/Sources/Runic/Views/Menu/ProjectBreakdownMenuView.swift +209 -0
  241. package/Sources/Runic/Views/Menu/ProjectBudgetMenuView.swift +220 -0
  242. package/Sources/Runic/Views/Menu/ProviderTabBarView.swift +88 -0
  243. package/Sources/Runic/Views/Menu/SubscriptionUtilizationChartMenuView.swift +201 -0
  244. package/Sources/Runic/Views/Menu/UsageBreakdownChartMenuView.swift +398 -0
  245. package/Sources/Runic/Views/Menu/UsageHeatmapMenuView.swift +232 -0
  246. package/Sources/Runic/Views/Menu/UsageTimelineChartMenuView.swift +417 -0
  247. package/Sources/Runic/Views/Menu/UsageWindowComparisonChartMenuView.swift +190 -0
  248. package/Sources/Runic/Views/Menu/WeeklyActivityChartMenuView.swift +132 -0
  249. package/Sources/Runic/Views/Performance/PerformanceDashboardView.swift +618 -0
  250. package/Sources/Runic/Views/Preferences/LiquidComponents.swift +305 -0
  251. package/Sources/Runic/Views/Preferences/PreferencesAboutPane.swift +271 -0
  252. package/Sources/Runic/Views/Preferences/PreferencesAdvancedPane.swift +268 -0
  253. package/Sources/Runic/Views/Preferences/PreferencesAlertsPane.swift +422 -0
  254. package/Sources/Runic/Views/Preferences/PreferencesAnalyticsPane.swift +641 -0
  255. package/Sources/Runic/Views/Preferences/PreferencesBudgetsPane.swift +344 -0
  256. package/Sources/Runic/Views/Preferences/PreferencesComponents.swift +230 -0
  257. package/Sources/Runic/Views/Preferences/PreferencesCustomProvidersPane.swift +322 -0
  258. package/Sources/Runic/Views/Preferences/PreferencesDebugPane.swift +469 -0
  259. package/Sources/Runic/Views/Preferences/PreferencesGeneralPane.swift +231 -0
  260. package/Sources/Runic/Views/Preferences/PreferencesHelpPane.swift +50 -0
  261. package/Sources/Runic/Views/Preferences/PreferencesIntegrationsPane.swift +497 -0
  262. package/Sources/Runic/Views/Preferences/PreferencesPerformancePane.swift +288 -0
  263. package/Sources/Runic/Views/Preferences/PreferencesProvidersPane.swift +3435 -0
  264. package/Sources/Runic/Views/Preferences/PreferencesSelection.swift +25 -0
  265. package/Sources/Runic/Views/Preferences/PreferencesSyncPane.swift +59 -0
  266. package/Sources/Runic/Views/Preferences/PreferencesView.swift +206 -0
  267. package/Sources/Runic/Views/Rating/QualityRatingView.swift +238 -0
  268. package/Sources/Runic/Views/Team/TeamDashboardView.swift +371 -0
  269. package/Sources/Runic/Views/Team/TeamInviteSheet.swift +175 -0
  270. package/Sources/Runic/Views/Team/TeamManagementView.swift +761 -0
  271. package/Sources/Runic/Views/Team/TeamMemberRow.swift +181 -0
  272. package/Sources/RunicCLI/CLIEntry.swift +942 -0
  273. package/Sources/RunicCLI/CLIRenderer.swift +87 -0
  274. package/Sources/RunicCLI/Commands/EnhancedUsageCommand.swift +588 -0
  275. package/Sources/RunicCLI/Commands/ModelsCommand.swift +362 -0
  276. package/Sources/RunicCLI/Commands/ProjectsCommand.swift +439 -0
  277. package/Sources/RunicCLI/Commands/ResetCommand.swift +429 -0
  278. package/Sources/RunicCLI/Commands/UsageLedgerSourceFactory.swift +168 -0
  279. package/Sources/RunicClaudeWatchdog/main.swift +122 -0
  280. package/Sources/RunicClaudeWebProbe/main.swift +62 -0
  281. package/Sources/RunicCore/AlertRuleStore.swift +187 -0
  282. package/Sources/RunicCore/BrowserCookieImportOrder.swift +25 -0
  283. package/Sources/RunicCore/CopilotUsageModels.swift +84 -0
  284. package/Sources/RunicCore/CostUsageFetcher.swift +119 -0
  285. package/Sources/RunicCore/CostUsageModels.swift +479 -0
  286. package/Sources/RunicCore/CreditsModels.swift +50 -0
  287. package/Sources/RunicCore/CustomProviders/CustomProviderModels.swift +269 -0
  288. package/Sources/RunicCore/CustomProviders/GenericProviderFetcher.swift +622 -0
  289. package/Sources/RunicCore/CustomProviders/ProviderTemplates.swift +500 -0
  290. package/Sources/RunicCore/Host/PTY/TTYCommandRunner.swift +679 -0
  291. package/Sources/RunicCore/Host/Process/SubprocessRunner.swift +135 -0
  292. package/Sources/RunicCore/Integrations/GitHubIntegration.swift +173 -0
  293. package/Sources/RunicCore/Logging/JSONStderrLogHandler.swift +79 -0
  294. package/Sources/RunicCore/Logging/OSLogLogHandler.swift +86 -0
  295. package/Sources/RunicCore/Logging/RunicLog.swift +123 -0
  296. package/Sources/RunicCore/Models/EnhancedUsageModels.swift +371 -0
  297. package/Sources/RunicCore/OpenAIDashboardModels.swift +210 -0
  298. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardBrowserCookieImporter.swift +676 -0
  299. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardFetcher.swift +492 -0
  300. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardNavigationDelegate.swift +51 -0
  301. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardParser.swift +483 -0
  302. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardScrapeScript.swift +558 -0
  303. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardWebViewCache.swift +204 -0
  304. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardWebsiteDataStore.swift +78 -0
  305. package/Sources/RunicCore/PathEnvironment.swift +482 -0
  306. package/Sources/RunicCore/Performance/PerformanceModels.swift +371 -0
  307. package/Sources/RunicCore/Performance/PerformanceStorageImpl.swift +409 -0
  308. package/Sources/RunicCore/Policy/UsagePolicyEngine.swift +178 -0
  309. package/Sources/RunicCore/ProjectBudgetStore.swift +99 -0
  310. package/Sources/RunicCore/ProviderCostSnapshot.swift +29 -0
  311. package/Sources/RunicCore/Providers/Antigravity/AntigravityProviderDescriptor.swift +66 -0
  312. package/Sources/RunicCore/Providers/Antigravity/AntigravityStatusProbe.swift +685 -0
  313. package/Sources/RunicCore/Providers/Auggie/AuggieProviderDescriptor.swift +83 -0
  314. package/Sources/RunicCore/Providers/Auggie/AuggieUsageFetcher.swift +142 -0
  315. package/Sources/RunicCore/Providers/Azure/AzureProviderDescriptor.swift +141 -0
  316. package/Sources/RunicCore/Providers/Azure/AzureUsageFetcher.swift +186 -0
  317. package/Sources/RunicCore/Providers/Bedrock/BedrockProviderDescriptor.swift +126 -0
  318. package/Sources/RunicCore/Providers/Bedrock/BedrockUsageFetcher.swift +168 -0
  319. package/Sources/RunicCore/Providers/Cerebras/CerebrasProviderDescriptor.swift +84 -0
  320. package/Sources/RunicCore/Providers/Cerebras/CerebrasUsageFetcher.swift +75 -0
  321. package/Sources/RunicCore/Providers/Claude/ClaudeCLISession.swift +332 -0
  322. package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthCredentials.swift +180 -0
  323. package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthUsageFetcher.swift +137 -0
  324. package/Sources/RunicCore/Providers/Claude/ClaudeProviderDescriptor.swift +207 -0
  325. package/Sources/RunicCore/Providers/Claude/ClaudeStatusProbe.swift +654 -0
  326. package/Sources/RunicCore/Providers/Claude/ClaudeUsageDataSource.swift +28 -0
  327. package/Sources/RunicCore/Providers/Claude/ClaudeUsageFetcher.swift +480 -0
  328. package/Sources/RunicCore/Providers/Claude/ClaudeWeb/ClaudeWebAPIFetcher.swift +780 -0
  329. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthCredentials.swift +146 -0
  330. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthUsageFetcher.swift +269 -0
  331. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexTokenRefresher.swift +100 -0
  332. package/Sources/RunicCore/Providers/Codex/CodexProviderDescriptor.swift +243 -0
  333. package/Sources/RunicCore/Providers/Codex/CodexStatusProbe.swift +125 -0
  334. package/Sources/RunicCore/Providers/Codex/CodexUsageDataSource.swift +24 -0
  335. package/Sources/RunicCore/Providers/Codex/CodexWebDashboardStrategy.swift +181 -0
  336. package/Sources/RunicCore/Providers/Cohere/CohereProviderDescriptor.swift +83 -0
  337. package/Sources/RunicCore/Providers/Cohere/CohereUsageFetcher.swift +85 -0
  338. package/Sources/RunicCore/Providers/Copilot/CopilotDeviceFlow.swift +123 -0
  339. package/Sources/RunicCore/Providers/Copilot/CopilotGitHubCLITokenReader.swift +114 -0
  340. package/Sources/RunicCore/Providers/Copilot/CopilotProviderDescriptor.swift +100 -0
  341. package/Sources/RunicCore/Providers/Copilot/CopilotUsageFetcher.swift +291 -0
  342. package/Sources/RunicCore/Providers/Copilot/CopilotVSCodeTokenReader.swift +386 -0
  343. package/Sources/RunicCore/Providers/Cursor/CursorProviderDescriptor.swift +65 -0
  344. package/Sources/RunicCore/Providers/Cursor/CursorStatusProbe.swift +594 -0
  345. package/Sources/RunicCore/Providers/DeepSeek/DeepSeekProviderDescriptor.swift +85 -0
  346. package/Sources/RunicCore/Providers/DeepSeek/DeepSeekUsageFetcher.swift +108 -0
  347. package/Sources/RunicCore/Providers/Factory/FactoryLocalStorageImporter.swift +398 -0
  348. package/Sources/RunicCore/Providers/Factory/FactoryProviderDescriptor.swift +65 -0
  349. package/Sources/RunicCore/Providers/Factory/FactoryStatusProbe.swift +1275 -0
  350. package/Sources/RunicCore/Providers/Fireworks/FireworksProviderDescriptor.swift +84 -0
  351. package/Sources/RunicCore/Providers/Fireworks/FireworksUsageFetcher.swift +75 -0
  352. package/Sources/RunicCore/Providers/Gemini/GeminiProviderDescriptor.swift +65 -0
  353. package/Sources/RunicCore/Providers/Gemini/GeminiStatusProbe.swift +835 -0
  354. package/Sources/RunicCore/Providers/Groq/GroqProviderDescriptor.swift +83 -0
  355. package/Sources/RunicCore/Providers/Groq/GroqUsageFetcher.swift +71 -0
  356. package/Sources/RunicCore/Providers/Kimi/KimiProviderDescriptor.swift +83 -0
  357. package/Sources/RunicCore/Providers/Kimi/KimiUsageFetcher.swift +77 -0
  358. package/Sources/RunicCore/Providers/MiniMax/MiniMaxProviderDescriptor.swift +92 -0
  359. package/Sources/RunicCore/Providers/MiniMax/MiniMaxSettingsReader.swift +54 -0
  360. package/Sources/RunicCore/Providers/MiniMax/MiniMaxUsageFetcher.swift +171 -0
  361. package/Sources/RunicCore/Providers/MiniMax/MiniMaxWebUsageFetcher.swift +911 -0
  362. package/Sources/RunicCore/Providers/Mistral/MistralProviderDescriptor.swift +84 -0
  363. package/Sources/RunicCore/Providers/Mistral/MistralUsageFetcher.swift +75 -0
  364. package/Sources/RunicCore/Providers/OpenRouter/OpenRouterProviderDescriptor.swift +87 -0
  365. package/Sources/RunicCore/Providers/OpenRouter/OpenRouterUsageFetcher.swift +207 -0
  366. package/Sources/RunicCore/Providers/Perplexity/PerplexityProviderDescriptor.swift +84 -0
  367. package/Sources/RunicCore/Providers/Perplexity/PerplexityUsageFetcher.swift +75 -0
  368. package/Sources/RunicCore/Providers/ProviderBranding.swift +25 -0
  369. package/Sources/RunicCore/Providers/ProviderCLIConfig.swift +17 -0
  370. package/Sources/RunicCore/Providers/ProviderDescriptor.swift +129 -0
  371. package/Sources/RunicCore/Providers/ProviderFetchPlan.swift +263 -0
  372. package/Sources/RunicCore/Providers/ProviderSettingsSnapshot.swift +98 -0
  373. package/Sources/RunicCore/Providers/ProviderTokenResolver.swift +501 -0
  374. package/Sources/RunicCore/Providers/ProviderVersionDetector.swift +68 -0
  375. package/Sources/RunicCore/Providers/Providers.swift +184 -0
  376. package/Sources/RunicCore/Providers/Qwen/QwenProviderDescriptor.swift +84 -0
  377. package/Sources/RunicCore/Providers/Qwen/QwenSettingsReader.swift +30 -0
  378. package/Sources/RunicCore/Providers/Qwen/QwenUsageStats.swift +317 -0
  379. package/Sources/RunicCore/Providers/SambaNova/SambaNovaProviderDescriptor.swift +84 -0
  380. package/Sources/RunicCore/Providers/SambaNova/SambaNovaUsageFetcher.swift +75 -0
  381. package/Sources/RunicCore/Providers/Together/TogetherProviderDescriptor.swift +83 -0
  382. package/Sources/RunicCore/Providers/Together/TogetherUsageFetcher.swift +75 -0
  383. package/Sources/RunicCore/Providers/VertexAI/VertexAIProviderDescriptor.swift +123 -0
  384. package/Sources/RunicCore/Providers/VertexAI/VertexAISettingsReader.swift +48 -0
  385. package/Sources/RunicCore/Providers/VertexAI/VertexAIUsageFetcher.swift +144 -0
  386. package/Sources/RunicCore/Providers/XAI/XAIProviderDescriptor.swift +83 -0
  387. package/Sources/RunicCore/Providers/XAI/XAIUsageFetcher.swift +75 -0
  388. package/Sources/RunicCore/Providers/Zai/ZaiProviderDescriptor.swift +72 -0
  389. package/Sources/RunicCore/Providers/Zai/ZaiSettingsReader.swift +41 -0
  390. package/Sources/RunicCore/Providers/Zai/ZaiUsageStats.swift +724 -0
  391. package/Sources/RunicCore/Sync/BackgroundSyncManager.swift +385 -0
  392. package/Sources/RunicCore/Sync/SyncConflictResolver.swift +310 -0
  393. package/Sources/RunicCore/Sync/SyncProtocol.swift +288 -0
  394. package/Sources/RunicCore/Sync/SyncRecord.swift +405 -0
  395. package/Sources/RunicCore/Sync/SyncUsageExample.swift +294 -0
  396. package/Sources/RunicCore/Sync/TeamSyncRecords.swift +775 -0
  397. package/Sources/RunicCore/Sync/iCloudSyncEngine.swift +333 -0
  398. package/Sources/RunicCore/Team/TeamModels.swift +583 -0
  399. package/Sources/RunicCore/Team/TeamShowbackExporter.swift +495 -0
  400. package/Sources/RunicCore/Team/TeamStore.swift +792 -0
  401. package/Sources/RunicCore/TextParsing.swift +55 -0
  402. package/Sources/RunicCore/UsageFetcher.swift +694 -0
  403. package/Sources/RunicCore/UsageFormatter.swift +410 -0
  404. package/Sources/RunicCore/UsageLedger/ClaudeUsageLogSource.swift +329 -0
  405. package/Sources/RunicCore/UsageLedger/CodexUsageLogSource.swift +448 -0
  406. package/Sources/RunicCore/UsageLedger/OTelGenAILedgerAdapter.swift +550 -0
  407. package/Sources/RunicCore/UsageLedger/UsageLedger.swift +29 -0
  408. package/Sources/RunicCore/UsageLedger/UsageLedgerAggregator.swift +660 -0
  409. package/Sources/RunicCore/UsageLedger/UsageLedgerInsightsAdvisor.swift +209 -0
  410. package/Sources/RunicCore/UsageLedger/UsageLedgerModels.swift +417 -0
  411. package/Sources/RunicCore/UsageLedger/UsageLedgerProjectIdentity.swift +245 -0
  412. package/Sources/RunicCore/UsagePace.swift +81 -0
  413. package/Sources/RunicCore/Vendored/CostUsage/CostUsageCache.swift +73 -0
  414. package/Sources/RunicCore/Vendored/CostUsage/CostUsageJsonl.swift +74 -0
  415. package/Sources/RunicCore/Vendored/CostUsage/CostUsagePricing.swift +208 -0
  416. package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner+Claude.swift +455 -0
  417. package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner+Timestamp.swift +132 -0
  418. package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner.swift +589 -0
  419. package/Sources/RunicCore/WidgetSnapshot.swift +183 -0
  420. package/Sources/RunicMacroSupport/ProviderRegistrationMacros.swift +14 -0
  421. package/Sources/RunicMacros/ProviderRegistrationMacros.swift +216 -0
  422. package/Sources/RunicWidget/RunicWidgetBundle.swift +79 -0
  423. package/Sources/RunicWidget/RunicWidgetProvider.swift +283 -0
  424. package/Sources/RunicWidget/RunicWidgetViews.swift +680 -0
  425. package/Tests/RunicTests/AntigravityStatusProbeTests.swift +50 -0
  426. package/Tests/RunicTests/AppDelegateTests.swift +43 -0
  427. package/Tests/RunicTests/BrowserCookieOrderLabelTests.swift +22 -0
  428. package/Tests/RunicTests/CLIArgumentParsingTests.swift +70 -0
  429. package/Tests/RunicTests/CLICostTests.swift +65 -0
  430. package/Tests/RunicTests/CLIProviderSelectionTests.swift +22 -0
  431. package/Tests/RunicTests/CLISnapshotTests.swift +72 -0
  432. package/Tests/RunicTests/CLIWebFallbackTests.swift +58 -0
  433. package/Tests/RunicTests/ClaudeOAuthTests.swift +164 -0
  434. package/Tests/RunicTests/ClaudeResilienceTests.swift +30 -0
  435. package/Tests/RunicTests/ClaudeUsageTests.swift +370 -0
  436. package/Tests/RunicTests/CodexOAuthTests.swift +122 -0
  437. package/Tests/RunicTests/CodexUsageLogSourceTests.swift +82 -0
  438. package/Tests/RunicTests/CopilotTokenResolverTests.swift +75 -0
  439. package/Tests/RunicTests/CopilotVSCodeTokenReaderTests.swift +75 -0
  440. package/Tests/RunicTests/CostUsageDecodingTests.swift +394 -0
  441. package/Tests/RunicTests/CostUsagePricingTests.swift +50 -0
  442. package/Tests/RunicTests/CostUsageScannerTests.swift +700 -0
  443. package/Tests/RunicTests/CursorStatusProbeTests.swift +323 -0
  444. package/Tests/RunicTests/FactoryStatusProbeTests.swift +69 -0
  445. package/Tests/RunicTests/GeminiAPITestHelpers.swift +94 -0
  446. package/Tests/RunicTests/GeminiLoginAlertTests.swift +28 -0
  447. package/Tests/RunicTests/GeminiStatusProbeAPITests.swift +283 -0
  448. package/Tests/RunicTests/GeminiStatusProbePlanTests.swift +279 -0
  449. package/Tests/RunicTests/GeminiStatusProbeTests.swift +233 -0
  450. package/Tests/RunicTests/GeminiTestEnvironment.swift +87 -0
  451. package/Tests/RunicTests/GoogleWorkspaceStatusTests.swift +73 -0
  452. package/Tests/RunicTests/InstallOriginTests.swift +18 -0
  453. package/Tests/RunicTests/KeyboardShortcutsBundleTests.swift +9 -0
  454. package/Tests/RunicTests/LiveAccountTests.swift +24 -0
  455. package/Tests/RunicTests/LoadingPatternTests.swift +35 -0
  456. package/Tests/RunicTests/MenuCardModelTests.swift +545 -0
  457. package/Tests/RunicTests/MiniMaxCookieHeaderStoreTestSupport.swift +8 -0
  458. package/Tests/RunicTests/MiniMaxGroupIDStoreTestSupport.swift +8 -0
  459. package/Tests/RunicTests/MiniMaxParsingTests.swift +68 -0
  460. package/Tests/RunicTests/MiniMaxTokenStoreTestSupport.swift +8 -0
  461. package/Tests/RunicTests/OTelGenAILedgerAdapterTests.swift +112 -0
  462. package/Tests/RunicTests/OpenAIDashboardBrowserCookieImporterTests.swift +17 -0
  463. package/Tests/RunicTests/OpenAIDashboardFetcherCreditsWaitTests.swift +75 -0
  464. package/Tests/RunicTests/OpenAIDashboardOffscreenHostTests.swift +27 -0
  465. package/Tests/RunicTests/OpenAIDashboardParserTests.swift +134 -0
  466. package/Tests/RunicTests/OpenAIWebAccountSwitchTests.swift +53 -0
  467. package/Tests/RunicTests/OpenRouterTokenStoreTestSupport.swift +92 -0
  468. package/Tests/RunicTests/PathBuilderTests.swift +237 -0
  469. package/Tests/RunicTests/ProviderFetchPipelineTests.swift +160 -0
  470. package/Tests/RunicTests/ProviderIconResourcesTests.swift +38 -0
  471. package/Tests/RunicTests/ProviderMetadataStatusLinkTests.swift +16 -0
  472. package/Tests/RunicTests/ProviderRegistryTests.swift +29 -0
  473. package/Tests/RunicTests/ProviderSettingsDescriptorTests.swift +202 -0
  474. package/Tests/RunicTests/ProviderToggleStoreTests.swift +51 -0
  475. package/Tests/RunicTests/RunicTests.swift +120 -0
  476. package/Tests/RunicTests/SessionQuotaNotificationLogicTests.swift +36 -0
  477. package/Tests/RunicTests/SettingsStoreTests.swift +161 -0
  478. package/Tests/RunicTests/StatusItemAnimationTests.swift +49 -0
  479. package/Tests/RunicTests/StatusMenuTests.swift +434 -0
  480. package/Tests/RunicTests/StatusProbeTests.swift +377 -0
  481. package/Tests/RunicTests/SubprocessRunnerTests.swift +20 -0
  482. package/Tests/RunicTests/SubscriptionDetectionTests.swift +65 -0
  483. package/Tests/RunicTests/TTYCommandRunnerTests.swift +148 -0
  484. package/Tests/RunicTests/TTYIntegrationTests.swift +41 -0
  485. package/Tests/RunicTests/TeamShowbackExporterTests.swift +159 -0
  486. package/Tests/RunicTests/TextParsingTests.swift +12 -0
  487. package/Tests/RunicTests/UsageFormatterTests.swift +112 -0
  488. package/Tests/RunicTests/UsageLedgerAnomalyDetectionTests.swift +172 -0
  489. package/Tests/RunicTests/UsageLedgerForecastTests.swift +213 -0
  490. package/Tests/RunicTests/UsageLedgerInsightsAdvisorTests.swift +83 -0
  491. package/Tests/RunicTests/UsageLedgerProjectNameTests.swift +170 -0
  492. package/Tests/RunicTests/UsagePaceTests.swift +77 -0
  493. package/Tests/RunicTests/UsagePaceTextTests.swift +109 -0
  494. package/Tests/RunicTests/UsagePolicyEngineTests.swift +91 -0
  495. package/Tests/RunicTests/WidgetSnapshotTests.swift +45 -0
  496. package/Tests/RunicTests/ZaiProviderTests.swift +61 -0
  497. package/Tests/RunicTests/ZaiTokenStoreTestSupport.swift +6 -0
  498. package/TestsLinux/PlatformGatingTests.swift +46 -0
  499. package/appcast.xml +105 -0
  500. package/assets/logo-concept-stack.svg +24 -0
  501. package/assets/logo-minimal-bars.svg +15 -0
  502. package/assets/logo.svg +20 -0
  503. package/assets/logo2.svg +43 -0
  504. package/bin/docs-list +5 -0
  505. package/bin/install-runic-cli.sh +32 -0
  506. package/build-and-run.sh +369 -0
  507. package/docs/.nojekyll +1 -0
  508. package/docs/CNAME +1 -0
  509. package/docs/antigravity.md +75 -0
  510. package/docs/architecture.md +32 -0
  511. package/docs/claude.md +93 -0
  512. package/docs/cli-commands/integration_guide.md +371 -0
  513. package/docs/cli-commands/quick_reference.md +362 -0
  514. package/docs/cli-commands/readme.md +361 -0
  515. package/docs/cli.md +156 -0
  516. package/docs/cloudkit_sync_guide.md +495 -0
  517. package/docs/codebase_review.md +288 -0
  518. package/docs/codex-oauth.md +635 -0
  519. package/docs/codex.md +104 -0
  520. package/docs/codexbar.png +0 -0
  521. package/docs/copilot.md +44 -0
  522. package/docs/cursor.md +46 -0
  523. package/docs/design/designcomparisonchart.md +510 -0
  524. package/docs/design/implementationguide.md +792 -0
  525. package/docs/design/menubaricondesignconcepts.md +796 -0
  526. package/docs/design/mockups/hybridiconconcept.svg +62 -0
  527. package/docs/design/mockups/infinityiconconcept.svg +41 -0
  528. package/docs/design/mockups/infinityiconstates.svg +129 -0
  529. package/docs/design/mockups/wavelogorefined.svg +48 -0
  530. package/docs/design/quick_summary.md +426 -0
  531. package/docs/design/readme.md +478 -0
  532. package/docs/design/sizespecifications.md +575 -0
  533. package/docs/design-system.md +836 -0
  534. package/docs/factory.md +103 -0
  535. package/docs/gemini.md +73 -0
  536. package/docs/icon.md +37 -0
  537. package/docs/icon.png +0 -0
  538. package/docs/index.html +175 -0
  539. package/docs/keychain_fix.md +274 -0
  540. package/docs/minimax.md +71 -0
  541. package/docs/packaging.md +25 -0
  542. package/docs/progress-bar-improvements.md +240 -0
  543. package/docs/progress-bar-quick-reference.md +283 -0
  544. package/docs/progress-bar-technical-details.md +432 -0
  545. package/docs/progress-bar-visual-test.swift +375 -0
  546. package/docs/provider.md +202 -0
  547. package/docs/providers.md +86 -0
  548. package/docs/refactor/macros.md +35 -0
  549. package/docs/refresh-loop.md +22 -0
  550. package/docs/releasing-homebrew.md +35 -0
  551. package/docs/releasing.md +121 -0
  552. package/docs/research/concrete_todo_2026-02-22.md +47 -0
  553. package/docs/research/core-feature-research.md +248 -0
  554. package/docs/research/feature_uiux_roadmap_2026-02-22.md +202 -0
  555. package/docs/research/parity_matrix.md +49 -0
  556. package/docs/research/provider_expansion_candidates_2026-02-22.md +80 -0
  557. package/docs/research/provider_model_token_project_matrix_2026-02-23.md +46 -0
  558. package/docs/research/release_gate_checklist.md +57 -0
  559. package/docs/site.css +505 -0
  560. package/docs/sparkle.md +28 -0
  561. package/docs/status.md +28 -0
  562. package/docs/sync/implementation.md +393 -0
  563. package/docs/sync/readme.md +317 -0
  564. package/docs/sync_files_summary.md +391 -0
  565. package/docs/sync_quick_reference.md +225 -0
  566. package/docs/todo.md +11 -0
  567. package/docs/ui.md +29 -0
  568. package/docs/web-integration.md +9 -0
  569. package/docs/widgets.md +85 -0
  570. package/docs/workflows/error-handling-improvements.md +434 -0
  571. package/docs/workflows/folder_structure.md +299 -0
  572. package/docs/workflows/loading_states.md +446 -0
  573. package/docs/workflows/loading_states_examples.md +565 -0
  574. package/docs/workflows/loading_states_flow.md +430 -0
  575. package/docs/workflows/performance_optimizations.md +457 -0
  576. package/docs/workflows/phase1-cli-testing-report.md +313 -0
  577. package/docs/workflows/quick_reference.md +228 -0
  578. package/docs/workflows/readme.md +59 -0
  579. package/docs/workflows/recent_improvements.md +275 -0
  580. package/docs/workflows/sync_enablement_summary.md +400 -0
  581. package/docs/zai.md +43 -0
  582. package/package.json +36 -0
  583. package/runic.png +0 -0
  584. package/version.env +2 -0
@@ -0,0 +1,193 @@
1
+ import AppKit
2
+ import RunicCore
3
+ import SwiftUI
4
+
5
+ @MainActor
6
+ struct CopilotLoginFlow {
7
+ static func run(settings: SettingsStore) async -> Bool {
8
+ let flow = CopilotDeviceFlow()
9
+
10
+ do {
11
+ let code = try await flow.requestDeviceCode()
12
+
13
+ // Copy code to clipboard
14
+ let pb = NSPasteboard.general
15
+ pb.clearContents()
16
+ pb.setString(code.userCode, forType: .string)
17
+
18
+ let alert = NSAlert()
19
+ alert.messageText = "GitHub Copilot Login"
20
+ alert.informativeText = """
21
+ A device code has been copied to your clipboard: \(code.userCode)
22
+
23
+ We will open GitHub with the code prefilled.
24
+ If the browser still asks for a code, paste: \(code.userCode)
25
+ """
26
+ alert.addButton(withTitle: "Open Browser")
27
+ alert.addButton(withTitle: "Cancel")
28
+
29
+ let response = alert.runModal()
30
+ if response == .alertSecondButtonReturn {
31
+ return false // Cancelled
32
+ }
33
+
34
+ if let url = Self.makeVerificationURL(code: code) {
35
+ NSWorkspace.shared.open(url)
36
+ }
37
+
38
+ // Poll in background (modal blocks, but we need to wait for token effectively)
39
+ // Ideally we'd show a "Waiting..." modal or spinner.
40
+ // For simplicity, we can use a non-modal window or just block a Task?
41
+ // `runModal` blocks the thread. We need to poll while the user is doing auth in browser.
42
+ // But we already returned from runModal to open the browser.
43
+ // We need a secondary "Waiting for confirmation..." alert or state.
44
+
45
+ // Let's show a "Waiting" alert that can be cancelled.
46
+ let waitingAlert = NSAlert()
47
+ waitingAlert.messageText = "Waiting for Authentication..."
48
+ waitingAlert.informativeText = """
49
+ Please complete the login in your browser.
50
+ This window will close automatically when finished.
51
+ """
52
+ waitingAlert.addButton(withTitle: "Cancel")
53
+ let parentWindow = Self.resolveWaitingParentWindow()
54
+ let hostWindow = parentWindow ?? Self.makeWaitingHostWindow()
55
+ let shouldCloseHostWindow = parentWindow == nil
56
+ let tokenTask = Task.detached(priority: .userInitiated) {
57
+ try await flow.pollForToken(deviceCode: code.deviceCode, interval: code.interval)
58
+ }
59
+
60
+ let waitTask = Task { @MainActor in
61
+ let response = await Self.presentWaitingAlert(waitingAlert, parentWindow: hostWindow)
62
+ if response == .alertFirstButtonReturn {
63
+ tokenTask.cancel()
64
+ }
65
+ return response
66
+ }
67
+
68
+ let tokenResult: Result<String, Error>
69
+ do {
70
+ let token = try await tokenTask.value
71
+ tokenResult = .success(token)
72
+ } catch {
73
+ tokenResult = .failure(error)
74
+ }
75
+
76
+ Self.dismissWaitingAlert(waitingAlert, parentWindow: hostWindow, closeHost: shouldCloseHostWindow)
77
+ let waitResponse = await waitTask.value
78
+ if waitResponse == .alertFirstButtonReturn {
79
+ return false
80
+ }
81
+
82
+ switch tokenResult {
83
+ case let .success(token):
84
+ settings.copilotAPIToken = token
85
+ settings.setProviderEnabled(
86
+ provider: .copilot,
87
+ metadata: ProviderRegistry.shared.metadata[.copilot]!,
88
+ enabled: true)
89
+
90
+ let success = NSAlert()
91
+ success.messageText = "Login Successful"
92
+ success.runModal()
93
+ return true
94
+ case let .failure(error):
95
+ guard !(error is CancellationError) else { return false }
96
+ let err = NSAlert()
97
+ err.messageText = "Login Failed"
98
+ err.informativeText = error.localizedDescription
99
+ err.runModal()
100
+ return false
101
+ }
102
+
103
+ } catch {
104
+ let err = NSAlert()
105
+ err.messageText = "Login Failed"
106
+ err.informativeText = error.localizedDescription
107
+ err.runModal()
108
+ return false
109
+ }
110
+ }
111
+
112
+ @MainActor
113
+ private static func presentWaitingAlert(
114
+ _ alert: NSAlert,
115
+ parentWindow: NSWindow) async -> NSApplication.ModalResponse
116
+ {
117
+ await withCheckedContinuation { continuation in
118
+ alert.beginSheetModal(for: parentWindow) { response in
119
+ continuation.resume(returning: response)
120
+ }
121
+ }
122
+ }
123
+
124
+ @MainActor
125
+ private static func dismissWaitingAlert(
126
+ _ alert: NSAlert,
127
+ parentWindow: NSWindow,
128
+ closeHost: Bool)
129
+ {
130
+ let alertWindow = alert.window
131
+ if alertWindow.sheetParent != nil {
132
+ parentWindow.endSheet(alertWindow)
133
+ } else {
134
+ alertWindow.orderOut(nil)
135
+ }
136
+
137
+ guard closeHost else { return }
138
+ parentWindow.orderOut(nil)
139
+ parentWindow.close()
140
+ }
141
+
142
+ @MainActor
143
+ private static func resolveWaitingParentWindow() -> NSWindow? {
144
+ if let window = NSApp.keyWindow ?? NSApp.mainWindow {
145
+ return window
146
+ }
147
+ if let window = NSApp.windows.first(where: { $0.isVisible && !$0.ignoresMouseEvents }) {
148
+ return window
149
+ }
150
+ return NSApp.windows.first
151
+ }
152
+
153
+ @MainActor
154
+ private static func makeWaitingHostWindow() -> NSWindow {
155
+ let window = NSWindow(
156
+ contentRect: NSRect(x: 0, y: 0, width: 420, height: 1),
157
+ styleMask: [.titled, .fullSizeContentView],
158
+ backing: .buffered,
159
+ defer: false)
160
+ window.isReleasedWhenClosed = false
161
+ window.titleVisibility = .hidden
162
+ window.titlebarAppearsTransparent = true
163
+ window.standardWindowButton(.closeButton)?.isHidden = true
164
+ window.standardWindowButton(.miniaturizeButton)?.isHidden = true
165
+ window.standardWindowButton(.zoomButton)?.isHidden = true
166
+ window.backgroundColor = .clear
167
+ window.isOpaque = false
168
+ window.hasShadow = false
169
+ window.level = .floating
170
+ window.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
171
+ window.center()
172
+ window.makeKeyAndOrderFront(nil)
173
+ return window
174
+ }
175
+
176
+ private static func makeVerificationURL(code: CopilotDeviceFlow.DeviceCodeResponse) -> URL? {
177
+ if let complete = code.verificationUriComplete,
178
+ let completeURL = URL(string: complete)
179
+ {
180
+ return completeURL
181
+ }
182
+
183
+ guard var components = URLComponents(string: code.verificationUri) else {
184
+ return URL(string: code.verificationUri)
185
+ }
186
+ var items = components.queryItems ?? []
187
+ if !items.contains(where: { $0.name.caseInsensitiveCompare("user_code") == .orderedSame }) {
188
+ items.append(URLQueryItem(name: "user_code", value: code.userCode))
189
+ }
190
+ components.queryItems = items
191
+ return components.url ?? URL(string: code.verificationUri)
192
+ }
193
+ }
@@ -0,0 +1,110 @@
1
+ import AppKit
2
+ import RunicCore
3
+ import RunicMacroSupport
4
+ import SwiftUI
5
+
6
+ @ProviderImplementationRegistration
7
+ struct CopilotProviderImplementation: ProviderImplementation {
8
+ let id: UsageProvider = .copilot
9
+ let supportsLoginFlow: Bool = true
10
+
11
+ @MainActor
12
+ func settingsFields(context: ProviderSettingsContext) -> [ProviderSettingsFieldDescriptor] {
13
+ [
14
+ ProviderSettingsFieldDescriptor(
15
+ id: "copilot-api-token",
16
+ title: "GitHub Login",
17
+ subtitle: "Stored in Keychain (encrypted). Sign in via GitHub Device Flow below.",
18
+ kind: .secure,
19
+ placeholder: "Sign in via button below",
20
+ binding: context.stringBinding(\.copilotAPIToken),
21
+ actions: [
22
+ ProviderSettingsActionDescriptor(
23
+ id: "copilot-import-vscode",
24
+ title: "Import VS Code login",
25
+ style: .link,
26
+ isVisible: { context.settings.copilotAPIToken.isEmpty },
27
+ perform: {
28
+ if let token = CopilotVSCodeTokenReader.token(allowUserInteraction: true) {
29
+ context.settings.copilotAPIToken = token
30
+ context.settings.setProviderEnabled(
31
+ provider: .copilot,
32
+ metadata: ProviderRegistry.shared.metadata[.copilot]!,
33
+ enabled: true)
34
+ let success = NSAlert()
35
+ success.messageText = "VS Code Login Imported"
36
+ success.informativeText = "Runic imported your GitHub Copilot token from VS Code."
37
+ success.runModal()
38
+ await context.store.refresh(trigger: .login)
39
+ return
40
+ }
41
+
42
+ let failure = NSAlert()
43
+ failure.messageText = "Import Failed"
44
+ failure.informativeText = """
45
+ Runic could not access VS Code Copilot credentials.
46
+ You can sign in directly using "Sign in with GitHub" below.
47
+ """
48
+ failure.runModal()
49
+ }),
50
+ ProviderSettingsActionDescriptor(
51
+ id: "copilot-import-gh-cli",
52
+ title: "Import GitHub CLI login",
53
+ style: .link,
54
+ isVisible: { context.settings.copilotAPIToken.isEmpty },
55
+ perform: {
56
+ if let token = CopilotGitHubCLITokenReader.token() {
57
+ context.settings.copilotAPIToken = token
58
+ context.settings.setProviderEnabled(
59
+ provider: .copilot,
60
+ metadata: ProviderRegistry.shared.metadata[.copilot]!,
61
+ enabled: true)
62
+ let success = NSAlert()
63
+ success.messageText = "GitHub CLI Login Imported"
64
+ success.informativeText = "Runic imported your GitHub Copilot token from GitHub CLI."
65
+ success.runModal()
66
+ await context.store.refresh(trigger: .login)
67
+ return
68
+ }
69
+
70
+ let failure = NSAlert()
71
+ failure.messageText = "Import Failed"
72
+ failure.informativeText = """
73
+ Runic could not find a valid GitHub CLI token.
74
+ Sign in with GitHub CLI (`gh auth login`) and retry, or use the GitHub sign in button.
75
+ """
76
+ failure.runModal()
77
+ }),
78
+ ProviderSettingsActionDescriptor(
79
+ id: "copilot-login",
80
+ title: "Sign in with GitHub",
81
+ style: .bordered,
82
+ isVisible: { context.settings.copilotAPIToken.isEmpty },
83
+ perform: {
84
+ let didLogin = await CopilotLoginFlow.run(settings: context.settings)
85
+ guard didLogin else { return }
86
+ await context.store.refresh(trigger: .login)
87
+ }),
88
+ ProviderSettingsActionDescriptor(
89
+ id: "copilot-relogin",
90
+ title: "Sign in again",
91
+ style: .link,
92
+ isVisible: { !context.settings.copilotAPIToken.isEmpty },
93
+ perform: {
94
+ let didLogin = await CopilotLoginFlow.run(settings: context.settings)
95
+ guard didLogin else { return }
96
+ await context.store.refresh(trigger: .login)
97
+ }),
98
+ ],
99
+ isVisible: nil),
100
+ ]
101
+ }
102
+
103
+ @MainActor
104
+ func runLoginFlow(context: ProviderLoginContext) async -> Bool {
105
+ let didLogin = await CopilotLoginFlow.run(settings: context.controller.settings)
106
+ guard didLogin else { return false }
107
+ await context.controller.store.refresh(trigger: .login)
108
+ return true
109
+ }
110
+ }
@@ -0,0 +1,28 @@
1
+ import RunicCore
2
+
3
+ @MainActor
4
+ extension StatusItemController {
5
+ func runCursorLoginFlow() async {
6
+ let cursorRunner = CursorLoginRunner()
7
+ let phaseHandler: @Sendable (CursorLoginRunner.Phase) -> Void = { [weak self] phase in
8
+ Task { @MainActor in
9
+ switch phase {
10
+ case .loading, .waitingLogin:
11
+ self?.loginPhase = .waitingBrowser
12
+ case .success, .failed:
13
+ self?.loginPhase = .idle
14
+ }
15
+ }
16
+ }
17
+ let result = await cursorRunner.run(onPhaseChange: phaseHandler)
18
+ guard !Task.isCancelled else { return }
19
+ self.loginPhase = .idle
20
+ self.presentCursorLoginResult(result)
21
+ let outcome = self.describe(result.outcome)
22
+ self.loginLogger.info("Cursor login", metadata: ["outcome": outcome])
23
+ print("[Runic] Cursor login outcome=\(outcome)")
24
+ if case .success = result.outcome {
25
+ self.postLoginNotification(for: .cursor)
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,15 @@
1
+ import RunicCore
2
+ import RunicMacroSupport
3
+ import Foundation
4
+
5
+ @ProviderImplementationRegistration
6
+ struct CursorProviderImplementation: ProviderImplementation {
7
+ let id: UsageProvider = .cursor
8
+ let supportsLoginFlow: Bool = true
9
+
10
+ @MainActor
11
+ func runLoginFlow(context: ProviderLoginContext) async -> Bool {
12
+ await context.controller.runCursorLoginFlow()
13
+ return true
14
+ }
15
+ }
@@ -0,0 +1,24 @@
1
+ import AppKit
2
+ import RunicCore
3
+ import RunicMacroSupport
4
+ import Foundation
5
+
6
+ @ProviderImplementationRegistration
7
+ struct DeepSeekProviderImplementation: ProviderImplementation {
8
+ let id: UsageProvider = .deepseek
9
+
10
+ @MainActor
11
+ func settingsFields(context: ProviderSettingsContext) -> [ProviderSettingsFieldDescriptor] {
12
+ [
13
+ ProviderSettingsFieldDescriptor(
14
+ id: "deepseek-api-token",
15
+ title: "API key",
16
+ subtitle: "Stored in Keychain (encrypted). Press Return to save.",
17
+ kind: .secure,
18
+ placeholder: "Paste key…",
19
+ binding: context.stringBinding(\.deepSeekAPIToken),
20
+ actions: [],
21
+ isVisible: nil),
22
+ ]
23
+ }
24
+ }
@@ -0,0 +1,12 @@
1
+ import AppKit
2
+ import RunicCore
3
+
4
+ @MainActor
5
+ extension StatusItemController {
6
+ func runFactoryLoginFlow() async {
7
+ // Open Factory login page in default browser
8
+ if let url = URL(string: "https://app.factory.ai") {
9
+ NSWorkspace.shared.open(url)
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,15 @@
1
+ import RunicCore
2
+ import RunicMacroSupport
3
+ import Foundation
4
+
5
+ @ProviderImplementationRegistration
6
+ struct FactoryProviderImplementation: ProviderImplementation {
7
+ let id: UsageProvider = .factory
8
+ let supportsLoginFlow: Bool = true
9
+
10
+ @MainActor
11
+ func runLoginFlow(context: ProviderLoginContext) async -> Bool {
12
+ await context.controller.runFactoryLoginFlow()
13
+ return true
14
+ }
15
+ }
@@ -0,0 +1,24 @@
1
+ import AppKit
2
+ import RunicCore
3
+ import RunicMacroSupport
4
+ import Foundation
5
+
6
+ @ProviderImplementationRegistration
7
+ struct FireworksProviderImplementation: ProviderImplementation {
8
+ let id: UsageProvider = .fireworks
9
+
10
+ @MainActor
11
+ func settingsFields(context: ProviderSettingsContext) -> [ProviderSettingsFieldDescriptor] {
12
+ [
13
+ ProviderSettingsFieldDescriptor(
14
+ id: "fireworks-api-token",
15
+ title: "API key",
16
+ subtitle: "Stored in Keychain (encrypted). Press Return to save.",
17
+ kind: .secure,
18
+ placeholder: "Paste key…",
19
+ binding: context.stringBinding(\.fireworksAPIToken),
20
+ actions: [],
21
+ isVisible: nil),
22
+ ]
23
+ }
24
+ }
@@ -0,0 +1,20 @@
1
+ import RunicCore
2
+
3
+ @MainActor
4
+ extension StatusItemController {
5
+ func runGeminiLoginFlow() async {
6
+ let store = self.store
7
+ let result = await GeminiLoginRunner.run {
8
+ Task { @MainActor in
9
+ await store.refresh(trigger: .login, forceTokenUsage: true)
10
+ print("[Runic] Auto-refreshed after Gemini auth")
11
+ }
12
+ }
13
+ guard !Task.isCancelled else { return }
14
+ self.loginPhase = .idle
15
+ self.presentGeminiLoginResult(result)
16
+ let outcome = self.describe(result.outcome)
17
+ self.loginLogger.info("Gemini login", metadata: ["outcome": outcome])
18
+ print("[Runic] Gemini login outcome=\(outcome)")
19
+ }
20
+ }
@@ -0,0 +1,15 @@
1
+ import RunicCore
2
+ import RunicMacroSupport
3
+ import Foundation
4
+
5
+ @ProviderImplementationRegistration
6
+ struct GeminiProviderImplementation: ProviderImplementation {
7
+ let id: UsageProvider = .gemini
8
+ let supportsLoginFlow: Bool = true
9
+
10
+ @MainActor
11
+ func runLoginFlow(context: ProviderLoginContext) async -> Bool {
12
+ await context.controller.runGeminiLoginFlow()
13
+ return false
14
+ }
15
+ }
@@ -0,0 +1,24 @@
1
+ import AppKit
2
+ import RunicCore
3
+ import RunicMacroSupport
4
+ import Foundation
5
+
6
+ @ProviderImplementationRegistration
7
+ struct GroqProviderImplementation: ProviderImplementation {
8
+ let id: UsageProvider = .groq
9
+
10
+ @MainActor
11
+ func settingsFields(context: ProviderSettingsContext) -> [ProviderSettingsFieldDescriptor] {
12
+ [
13
+ ProviderSettingsFieldDescriptor(
14
+ id: "groq-api-token",
15
+ title: "API key",
16
+ subtitle: "Stored in Keychain (encrypted). Press Return to save.",
17
+ kind: .secure,
18
+ placeholder: "Paste key…",
19
+ binding: context.stringBinding(\.groqAPIToken),
20
+ actions: [],
21
+ isVisible: nil),
22
+ ]
23
+ }
24
+ }
@@ -0,0 +1,24 @@
1
+ import AppKit
2
+ import RunicCore
3
+ import RunicMacroSupport
4
+ import Foundation
5
+
6
+ @ProviderImplementationRegistration
7
+ struct KimiProviderImplementation: ProviderImplementation {
8
+ let id: UsageProvider = .kimi
9
+
10
+ @MainActor
11
+ func settingsFields(context: ProviderSettingsContext) -> [ProviderSettingsFieldDescriptor] {
12
+ [
13
+ ProviderSettingsFieldDescriptor(
14
+ id: "kimi-api-token",
15
+ title: "API key",
16
+ subtitle: "Stored in Keychain (encrypted). Press Return to save.",
17
+ kind: .secure,
18
+ placeholder: "Paste key…",
19
+ binding: context.stringBinding(\.kimiAPIToken),
20
+ actions: [],
21
+ isVisible: nil),
22
+ ]
23
+ }
24
+ }
@@ -0,0 +1,32 @@
1
+ import RunicCore
2
+ import RunicMacroSupport
3
+ import Foundation
4
+
5
+ @ProviderImplementationRegistration
6
+ struct MiniMaxProviderImplementation: ProviderImplementation {
7
+ let id: UsageProvider = .minimax
8
+
9
+ @MainActor
10
+ func settingsFields(context: ProviderSettingsContext) -> [ProviderSettingsFieldDescriptor] {
11
+ [
12
+ ProviderSettingsFieldDescriptor(
13
+ id: "minimax-api-token",
14
+ title: "API Token",
15
+ subtitle: "Enter your MiniMax API Key.",
16
+ kind: .secure,
17
+ placeholder: "ey...",
18
+ binding: context.stringBinding(\.minimaxAPIToken),
19
+ actions: [],
20
+ isVisible: nil),
21
+ ProviderSettingsFieldDescriptor(
22
+ id: "minimax-cookie-header",
23
+ title: "Cookie header (manual)",
24
+ subtitle: "Paste a Cookie: header or Copy as cURL. Stored in Keychain. Press Return to save.",
25
+ kind: .secure,
26
+ placeholder: "Paste Cookie header or cURL…",
27
+ binding: context.stringBinding(\.minimaxCookieHeader),
28
+ actions: [],
29
+ isVisible: nil),
30
+ ]
31
+ }
32
+ }
@@ -0,0 +1,24 @@
1
+ import AppKit
2
+ import RunicCore
3
+ import RunicMacroSupport
4
+ import Foundation
5
+
6
+ @ProviderImplementationRegistration
7
+ struct MistralProviderImplementation: ProviderImplementation {
8
+ let id: UsageProvider = .mistral
9
+
10
+ @MainActor
11
+ func settingsFields(context: ProviderSettingsContext) -> [ProviderSettingsFieldDescriptor] {
12
+ [
13
+ ProviderSettingsFieldDescriptor(
14
+ id: "mistral-api-token",
15
+ title: "API key",
16
+ subtitle: "Stored in Keychain (encrypted). Press Return to save.",
17
+ kind: .secure,
18
+ placeholder: "Paste key…",
19
+ binding: context.stringBinding(\.mistralAPIToken),
20
+ actions: [],
21
+ isVisible: nil),
22
+ ]
23
+ }
24
+ }
@@ -0,0 +1,24 @@
1
+ import AppKit
2
+ import RunicCore
3
+ import RunicMacroSupport
4
+ import Foundation
5
+
6
+ @ProviderImplementationRegistration
7
+ struct OpenRouterProviderImplementation: ProviderImplementation {
8
+ let id: UsageProvider = .openrouter
9
+
10
+ @MainActor
11
+ func settingsFields(context: ProviderSettingsContext) -> [ProviderSettingsFieldDescriptor] {
12
+ [
13
+ ProviderSettingsFieldDescriptor(
14
+ id: "openrouter-api-token",
15
+ title: "API key",
16
+ subtitle: "Stored in Keychain (encrypted). Press Return to save.",
17
+ kind: .secure,
18
+ placeholder: "Paste key…",
19
+ binding: context.stringBinding(\.openRouterAPIToken),
20
+ actions: [],
21
+ isVisible: nil),
22
+ ]
23
+ }
24
+ }
@@ -0,0 +1,24 @@
1
+ import AppKit
2
+ import RunicCore
3
+ import RunicMacroSupport
4
+ import Foundation
5
+
6
+ @ProviderImplementationRegistration
7
+ struct PerplexityProviderImplementation: ProviderImplementation {
8
+ let id: UsageProvider = .perplexity
9
+
10
+ @MainActor
11
+ func settingsFields(context: ProviderSettingsContext) -> [ProviderSettingsFieldDescriptor] {
12
+ [
13
+ ProviderSettingsFieldDescriptor(
14
+ id: "perplexity-api-token",
15
+ title: "API key",
16
+ subtitle: "Stored in Keychain (encrypted). Press Return to save.",
17
+ kind: .secure,
18
+ placeholder: "Paste key…",
19
+ binding: context.stringBinding(\.perplexityAPIToken),
20
+ actions: [],
21
+ isVisible: nil),
22
+ ]
23
+ }
24
+ }
@@ -0,0 +1,24 @@
1
+ import AppKit
2
+ import RunicCore
3
+ import RunicMacroSupport
4
+ import Foundation
5
+
6
+ @ProviderImplementationRegistration
7
+ struct SambaNovaProviderImplementation: ProviderImplementation {
8
+ let id: UsageProvider = .sambanova
9
+
10
+ @MainActor
11
+ func settingsFields(context: ProviderSettingsContext) -> [ProviderSettingsFieldDescriptor] {
12
+ [
13
+ ProviderSettingsFieldDescriptor(
14
+ id: "sambanova-api-token",
15
+ title: "API key",
16
+ subtitle: "Stored in Keychain (encrypted). Press Return to save.",
17
+ kind: .secure,
18
+ placeholder: "Paste key…",
19
+ binding: context.stringBinding(\.sambaNovaAPIToken),
20
+ actions: [],
21
+ isVisible: nil),
22
+ ]
23
+ }
24
+ }
@@ -0,0 +1,15 @@
1
+ import RunicCore
2
+
3
+ /// Source of truth for app-side provider implementations.
4
+ ///
5
+ /// Keep provider registration centralized here. The rest of the app should *not* have to be updated when a new
6
+ /// provider is added, aside from enum/metadata work in `RunicCore`.
7
+ enum ProviderCatalog {
8
+ /// All provider implementations shipped in the app.
9
+ static let all: [any ProviderImplementation] = ProviderImplementationRegistry.all
10
+
11
+ /// Lookup for a single provider implementation.
12
+ static func implementation(for id: UsageProvider) -> (any ProviderImplementation)? {
13
+ ProviderImplementationRegistry.implementation(for: id)
14
+ }
15
+ }