@sriinnu/runic 1.0.0

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