@sriinnu/runic 2.0.0 → 2.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (610) hide show
  1. package/CHANGELOG.md +261 -0
  2. package/LICENSE +373 -21
  3. package/README.md +96 -89
  4. package/THIRD-PARTY-NOTICES.md +651 -0
  5. package/package.json +14 -4
  6. package/.swiftformat +0 -50
  7. package/.swiftlint.yml +0 -160
  8. package/CONTRIBUTING.md +0 -456
  9. package/Icon.icns +0 -0
  10. package/Icon.icon/Assets/runic.png +0 -0
  11. package/Icon.icon/icon.json +0 -36
  12. package/Package.resolved +0 -51
  13. package/Package.swift +0 -136
  14. package/Packages/Helix/LICENSE +0 -21
  15. package/Packages/Helix/Package.swift +0 -29
  16. package/Packages/Helix/README.md +0 -976
  17. package/Packages/Helix/Sources/Helix/Binding.swift +0 -111
  18. package/Packages/Helix/Sources/Helix/CommandParser.swift +0 -160
  19. package/Packages/Helix/Sources/Helix/CommandSignature.swift +0 -117
  20. package/Packages/Helix/Sources/Helix/ExpressibleFromArgument.swift +0 -72
  21. package/Packages/Helix/Sources/Helix/HelpGenerator.swift +0 -175
  22. package/Packages/Helix/Sources/Helix/NameSpecification.swift +0 -98
  23. package/Packages/Helix/Sources/Helix/ParsableCommand.swift +0 -204
  24. package/Packages/Helix/Sources/Helix/Platform/DarwinPlatformContext.swift +0 -44
  25. package/Packages/Helix/Sources/Helix/Platform/LinuxPlatformContext.swift +0 -34
  26. package/Packages/Helix/Sources/Helix/Platform/PlatformContext+Default.swift +0 -91
  27. package/Packages/Helix/Sources/Helix/Platform/PlatformContext.swift +0 -94
  28. package/Packages/Helix/Sources/Helix/Platform/PlatformPath.swift +0 -167
  29. package/Packages/Helix/Sources/Helix/Platform/Stdio.swift +0 -99
  30. package/Packages/Helix/Sources/Helix/Platform/WebPlatformContext.swift +0 -146
  31. package/Packages/Helix/Sources/Helix/Platform/WindowsPlatformContext.swift +0 -97
  32. package/Packages/Helix/Sources/Helix/Program.swift +0 -204
  33. package/Packages/Helix/Sources/Helix/PropertyWrappers.swift +0 -367
  34. package/Packages/Silo/LICENSE +0 -21
  35. package/Packages/Silo/Package.swift +0 -34
  36. package/Packages/Silo/README.md +0 -466
  37. package/Packages/Silo/Sources/Silo/BinaryCookiesReader.swift +0 -169
  38. package/Packages/Silo/Sources/Silo/BrowserCookieAnalytics.swift +0 -365
  39. package/Packages/Silo/Sources/Silo/BrowserCookieBackends.swift +0 -594
  40. package/Packages/Silo/Sources/Silo/BrowserCookieClient.swift +0 -326
  41. package/Packages/Silo/Sources/Silo/BrowserCookieExport.swift +0 -154
  42. package/Packages/Silo/Sources/Silo/BrowserCookieImport.swift +0 -119
  43. package/Packages/Silo/Sources/Silo/BrowserCookieMockStore.swift +0 -121
  44. package/Packages/Silo/Sources/Silo/BrowserCookieModels.swift +0 -391
  45. package/Packages/Silo/Sources/Silo/ChromiumCookieReader.swift +0 -240
  46. package/Packages/Silo/Sources/Silo/CryptoSupport.swift +0 -86
  47. package/Packages/Silo/Sources/Silo/FirefoxCookieReader.swift +0 -172
  48. package/Packages/Silo/Sources/Silo/LinuxChromiumCookieReader.swift +0 -172
  49. package/Packages/Silo/Sources/Silo/LinuxSecretService.swift +0 -105
  50. package/Packages/Silo/Sources/Silo/MacOSChromiumCookieReader.swift +0 -191
  51. package/Packages/Silo/Sources/Silo/SQLiteSnapshot.swift +0 -41
  52. package/Packages/Silo/Sources/Silo/WindowsChromiumCookieReader.swift +0 -110
  53. package/RuniciOS/App/RuniciOSApp.swift +0 -105
  54. package/RuniciOS/Core/RunicTypographyiOS.swift +0 -24
  55. package/RuniciOS/Core/iOSUsageStore.swift +0 -192
  56. package/RuniciOS/Views/ProviderDetailView.swift +0 -312
  57. package/RuniciOS/Views/ProviderListView.swift +0 -228
  58. package/RuniciOS/Widgets/LargeWidget.swift +0 -367
  59. package/RuniciOS/Widgets/LiveActivity.swift +0 -342
  60. package/RuniciOS/Widgets/LockScreenWidget.swift +0 -273
  61. package/RuniciOS/Widgets/MediumWidget.swift +0 -370
  62. package/RuniciOS/Widgets/RunicWidget.swift +0 -274
  63. package/RuniciOS/Widgets/SmallWidget.swift +0 -281
  64. package/RuniciOS/Widgets/WidgetModels.swift +0 -285
  65. package/RuniciOS/Widgets/WidgetTimeline.swift +0 -270
  66. package/Scripts/CREATION-SUMMARY.md +0 -367
  67. package/Scripts/DIRECTORY-STRUCTURE.md +0 -358
  68. package/Scripts/GETTING-STARTED-CHECKLIST.md +0 -364
  69. package/Scripts/INDEX.md +0 -365
  70. package/Scripts/QUICK-REFERENCE.md +0 -164
  71. package/Scripts/README-SCRIPTS.md +0 -926
  72. package/Scripts/build-android.sh +0 -526
  73. package/Scripts/build-ios.sh +0 -529
  74. package/Scripts/build-macos.sh +0 -603
  75. package/Scripts/build-windows.sh +0 -504
  76. package/Scripts/build_icon.sh +0 -49
  77. package/Scripts/changelog-to-html.sh +0 -89
  78. package/Scripts/check-release-assets.sh +0 -10
  79. package/Scripts/ci-config.yml +0 -474
  80. package/Scripts/compile_and_run.sh +0 -219
  81. package/Scripts/compile_and_run_adhoc.sh +0 -4
  82. package/Scripts/docs-list.mjs +0 -119
  83. package/Scripts/make_appcast.sh +0 -58
  84. package/Scripts/package_app.sh +0 -409
  85. package/Scripts/release-lib.sh +0 -214
  86. package/Scripts/release.sh +0 -76
  87. package/Scripts/setup-all.sh +0 -387
  88. package/Scripts/setup-ios.sh +0 -404
  89. package/Scripts/setup-react-native.sh +0 -523
  90. package/Scripts/sign-and-notarize.sh +0 -122
  91. package/Scripts/test_live_update.sh +0 -38
  92. package/Scripts/validate_changelog.sh +0 -23
  93. package/Scripts/verify_appcast.sh +0 -92
  94. package/Sources/Runic/About.swift +0 -93
  95. package/Sources/Runic/AppNotifications.swift +0 -117
  96. package/Sources/Runic/Controllers/StatusItemController+Actions.swift +0 -670
  97. package/Sources/Runic/Controllers/StatusItemController+Animation.swift +0 -519
  98. package/Sources/Runic/Controllers/StatusItemController+ChartSubmenus.swift +0 -824
  99. package/Sources/Runic/Controllers/StatusItemController+CustomProviders.swift +0 -90
  100. package/Sources/Runic/Controllers/StatusItemController+Menu.swift +0 -1412
  101. package/Sources/Runic/Controllers/StatusItemController+MenuCards.swift +0 -339
  102. package/Sources/Runic/Controllers/StatusItemController+MenuHelpers.swift +0 -423
  103. package/Sources/Runic/Controllers/StatusItemController.swift +0 -360
  104. package/Sources/Runic/Core/BudgetNotificationManager.swift +0 -81
  105. package/Sources/Runic/Core/Login/ClaudeLoginRunner.swift +0 -103
  106. package/Sources/Runic/Core/Login/CodexLoginRunner.swift +0 -154
  107. package/Sources/Runic/Core/Login/CursorLoginRunner.swift +0 -206
  108. package/Sources/Runic/Core/Login/GeminiLoginRunner.swift +0 -92
  109. package/Sources/Runic/Core/Rendering/IconRenderer.swift +0 -1222
  110. package/Sources/Runic/Core/Rendering/IconView.swift +0 -122
  111. package/Sources/Runic/Core/Rendering/ProviderBrandIcon.swift +0 -71
  112. package/Sources/Runic/Core/RunicAnimation.swift +0 -53
  113. package/Sources/Runic/Core/RunicColors.swift +0 -73
  114. package/Sources/Runic/Core/RunicCornerRadius.swift +0 -15
  115. package/Sources/Runic/Core/RunicSpacing.swift +0 -68
  116. package/Sources/Runic/Core/RunicTypography.swift +0 -206
  117. package/Sources/Runic/Core/Stores/AuggieTokenStore.swift +0 -117
  118. package/Sources/Runic/Core/Stores/AzureOpenAITokenStore.swift +0 -117
  119. package/Sources/Runic/Core/Stores/CerebrasTokenStore.swift +0 -117
  120. package/Sources/Runic/Core/Stores/CohereTokenStore.swift +0 -117
  121. package/Sources/Runic/Core/Stores/CopilotTokenStore.swift +0 -117
  122. package/Sources/Runic/Core/Stores/CustomProviderStore.swift +0 -158
  123. package/Sources/Runic/Core/Stores/DeepSeekTokenStore.swift +0 -117
  124. package/Sources/Runic/Core/Stores/FireworksTokenStore.swift +0 -117
  125. package/Sources/Runic/Core/Stores/GroqTokenStore.swift +0 -117
  126. package/Sources/Runic/Core/Stores/KimiTokenStore.swift +0 -117
  127. package/Sources/Runic/Core/Stores/MiniMaxCookieHeaderStore.swift +0 -117
  128. package/Sources/Runic/Core/Stores/MiniMaxGroupIDStore.swift +0 -117
  129. package/Sources/Runic/Core/Stores/MiniMaxTokenStore.swift +0 -117
  130. package/Sources/Runic/Core/Stores/MistralTokenStore.swift +0 -117
  131. package/Sources/Runic/Core/Stores/OpenRouterTokenStore.swift +0 -117
  132. package/Sources/Runic/Core/Stores/PerplexityTokenStore.swift +0 -117
  133. package/Sources/Runic/Core/Stores/ProviderToggleStore.swift +0 -30
  134. package/Sources/Runic/Core/Stores/QwenTokenStore.swift +0 -117
  135. package/Sources/Runic/Core/Stores/SambaNovaTokenStore.swift +0 -117
  136. package/Sources/Runic/Core/Stores/SettingsStore.swift +0 -1749
  137. package/Sources/Runic/Core/Stores/TogetherTokenStore.swift +0 -117
  138. package/Sources/Runic/Core/Stores/UsageStore+Accessors.swift +0 -33
  139. package/Sources/Runic/Core/Stores/UsageStore+Status.swift +0 -189
  140. package/Sources/Runic/Core/Stores/UsageStore+TokenCost.swift +0 -33
  141. package/Sources/Runic/Core/Stores/UsageStore+WidgetSnapshot.swift +0 -67
  142. package/Sources/Runic/Core/Stores/UsageStore.swift +0 -3631
  143. package/Sources/Runic/Core/Stores/XAITokenStore.swift +0 -117
  144. package/Sources/Runic/Core/Stores/ZaiTokenStore.swift +0 -117
  145. package/Sources/Runic/Core/UsageExporter.swift +0 -197
  146. package/Sources/Runic/Date+RelativeDescription.swift +0 -21
  147. package/Sources/Runic/HiddenWindowView.swift +0 -32
  148. package/Sources/Runic/InstallOrigin.swift +0 -9
  149. package/Sources/Runic/KeyboardShortcuts+Names.swift +0 -6
  150. package/Sources/Runic/MouseLocationReader.swift +0 -65
  151. package/Sources/Runic/Notifications+Runic.swift +0 -6
  152. package/Sources/Runic/OpenAICreditsPurchaseWindowController.swift +0 -503
  153. package/Sources/Runic/ProviderRegistry.swift +0 -100
  154. package/Sources/Runic/ProviderSwitcherButtons.swift +0 -267
  155. package/Sources/Runic/Providers/Antigravity/AntigravityLoginFlow.swift +0 -11
  156. package/Sources/Runic/Providers/Antigravity/AntigravityProviderImplementation.swift +0 -14
  157. package/Sources/Runic/Providers/Auggie/AuggieProviderImplementation.swift +0 -24
  158. package/Sources/Runic/Providers/Azure/AzureProviderImplementation.swift +0 -52
  159. package/Sources/Runic/Providers/Bedrock/BedrockProviderImplementation.swift +0 -42
  160. package/Sources/Runic/Providers/Cerebras/CerebrasProviderImplementation.swift +0 -24
  161. package/Sources/Runic/Providers/Claude/ClaudeLoginFlow.swift +0 -26
  162. package/Sources/Runic/Providers/Claude/ClaudeProviderImplementation.swift +0 -14
  163. package/Sources/Runic/Providers/Codex/CodexLoginFlow.swift +0 -18
  164. package/Sources/Runic/Providers/Codex/CodexProviderImplementation.swift +0 -15
  165. package/Sources/Runic/Providers/Cohere/CohereProviderImplementation.swift +0 -24
  166. package/Sources/Runic/Providers/Copilot/CopilotLoginFlow.swift +0 -193
  167. package/Sources/Runic/Providers/Copilot/CopilotProviderImplementation.swift +0 -110
  168. package/Sources/Runic/Providers/Cursor/CursorLoginFlow.swift +0 -28
  169. package/Sources/Runic/Providers/Cursor/CursorProviderImplementation.swift +0 -15
  170. package/Sources/Runic/Providers/DeepSeek/DeepSeekProviderImplementation.swift +0 -24
  171. package/Sources/Runic/Providers/Factory/FactoryLoginFlow.swift +0 -12
  172. package/Sources/Runic/Providers/Factory/FactoryProviderImplementation.swift +0 -15
  173. package/Sources/Runic/Providers/Fireworks/FireworksProviderImplementation.swift +0 -24
  174. package/Sources/Runic/Providers/Gemini/GeminiLoginFlow.swift +0 -20
  175. package/Sources/Runic/Providers/Gemini/GeminiProviderImplementation.swift +0 -15
  176. package/Sources/Runic/Providers/Groq/GroqProviderImplementation.swift +0 -24
  177. package/Sources/Runic/Providers/Kimi/KimiProviderImplementation.swift +0 -24
  178. package/Sources/Runic/Providers/MiniMax/MiniMaxProviderImplementation.swift +0 -32
  179. package/Sources/Runic/Providers/Mistral/MistralProviderImplementation.swift +0 -24
  180. package/Sources/Runic/Providers/OpenRouter/OpenRouterProviderImplementation.swift +0 -24
  181. package/Sources/Runic/Providers/Perplexity/PerplexityProviderImplementation.swift +0 -24
  182. package/Sources/Runic/Providers/SambaNova/SambaNovaProviderImplementation.swift +0 -24
  183. package/Sources/Runic/Providers/Shared/ProviderCatalog.swift +0 -15
  184. package/Sources/Runic/Providers/Shared/ProviderImplementation.swift +0 -51
  185. package/Sources/Runic/Providers/Shared/ProviderImplementationRegistry.swift +0 -66
  186. package/Sources/Runic/Providers/Shared/ProviderLoginFlow.swift +0 -12
  187. package/Sources/Runic/Providers/Shared/ProviderSettingsDescriptors.swift +0 -99
  188. package/Sources/Runic/Providers/Shared/SystemSettingsLinks.swift +0 -18
  189. package/Sources/Runic/Providers/Together/TogetherProviderImplementation.swift +0 -24
  190. package/Sources/Runic/Providers/XAI/XAIProviderImplementation.swift +0 -24
  191. package/Sources/Runic/Providers/Zai/ZaiProviderImplementation.swift +0 -24
  192. package/Sources/Runic/Resources/Fonts/Caveat-Bold.ttf +0 -0
  193. package/Sources/Runic/Resources/Fonts/Caveat-Regular.ttf +0 -0
  194. package/Sources/Runic/Resources/Fonts/FiraCode-Bold.ttf +0 -0
  195. package/Sources/Runic/Resources/Fonts/FiraCode-Light.ttf +0 -0
  196. package/Sources/Runic/Resources/Fonts/FiraCode-Medium.ttf +0 -0
  197. package/Sources/Runic/Resources/Fonts/FiraCode-Regular.ttf +0 -0
  198. package/Sources/Runic/Resources/Fonts/FiraCode-SemiBold.ttf +0 -0
  199. package/Sources/Runic/Resources/Fonts/IBMPlexMono-Bold.ttf +0 -0
  200. package/Sources/Runic/Resources/Fonts/IBMPlexMono-Medium.ttf +0 -0
  201. package/Sources/Runic/Resources/Fonts/IBMPlexMono-Regular.ttf +0 -0
  202. package/Sources/Runic/Resources/Fonts/IBMPlexMono-SemiBold.ttf +0 -0
  203. package/Sources/Runic/Resources/Fonts/Inconsolata-Bold.ttf +0 -0
  204. package/Sources/Runic/Resources/Fonts/Inconsolata-Medium.ttf +0 -0
  205. package/Sources/Runic/Resources/Fonts/Inconsolata-Regular.ttf +0 -0
  206. package/Sources/Runic/Resources/Fonts/Inconsolata-SemiBold.ttf +0 -0
  207. package/Sources/Runic/Resources/Fonts/JetBrainsMono-Bold.ttf +0 -0
  208. package/Sources/Runic/Resources/Fonts/JetBrainsMono-Medium.ttf +0 -0
  209. package/Sources/Runic/Resources/Fonts/JetBrainsMono-Regular.ttf +0 -0
  210. package/Sources/Runic/Resources/Fonts/JetBrainsMono-SemiBold.ttf +0 -0
  211. package/Sources/Runic/Resources/Fonts/SpaceMono-Bold.ttf +0 -0
  212. package/Sources/Runic/Resources/Fonts/SpaceMono-Regular.ttf +0 -0
  213. package/Sources/Runic/Resources/ProviderIcon-antigravity.svg +0 -2
  214. package/Sources/Runic/Resources/ProviderIcon-auggie.svg +0 -3
  215. package/Sources/Runic/Resources/ProviderIcon-azure.svg +0 -5
  216. package/Sources/Runic/Resources/ProviderIcon-bedrock.svg +0 -7
  217. package/Sources/Runic/Resources/ProviderIcon-cerebras.svg +0 -3
  218. package/Sources/Runic/Resources/ProviderIcon-claude.svg +0 -1
  219. package/Sources/Runic/Resources/ProviderIcon-codex.svg +0 -1
  220. package/Sources/Runic/Resources/ProviderIcon-cohere.svg +0 -3
  221. package/Sources/Runic/Resources/ProviderIcon-copilot.svg +0 -1
  222. package/Sources/Runic/Resources/ProviderIcon-cursor.svg +0 -3
  223. package/Sources/Runic/Resources/ProviderIcon-deepseek.svg +0 -4
  224. package/Sources/Runic/Resources/ProviderIcon-factory.svg +0 -3
  225. package/Sources/Runic/Resources/ProviderIcon-fireworks.svg +0 -3
  226. package/Sources/Runic/Resources/ProviderIcon-gemini.svg +0 -1
  227. package/Sources/Runic/Resources/ProviderIcon-groq.svg +0 -1
  228. package/Sources/Runic/Resources/ProviderIcon-kimi.svg +0 -4
  229. package/Sources/Runic/Resources/ProviderIcon-minimax.svg +0 -1
  230. package/Sources/Runic/Resources/ProviderIcon-mistral.svg +0 -5
  231. package/Sources/Runic/Resources/ProviderIcon-openrouter.svg +0 -7
  232. package/Sources/Runic/Resources/ProviderIcon-perplexity.svg +0 -4
  233. package/Sources/Runic/Resources/ProviderIcon-qwen.svg +0 -9
  234. package/Sources/Runic/Resources/ProviderIcon-sambanova.svg +0 -4
  235. package/Sources/Runic/Resources/ProviderIcon-together.svg +0 -5
  236. package/Sources/Runic/Resources/ProviderIcon-vertexai.svg +0 -17
  237. package/Sources/Runic/Resources/ProviderIcon-xai.svg +0 -3
  238. package/Sources/Runic/Resources/ProviderIcon-zai.svg +0 -5
  239. package/Sources/Runic/Resources/RunicMenubarIcon.svg +0 -7
  240. package/Sources/Runic/Resources/provider-context-windows.json +0 -20
  241. package/Sources/Runic/RunicApp.swift +0 -367
  242. package/Sources/Runic/SessionQuotaNotifications.swift +0 -58
  243. package/Sources/Runic/UsagePaceText.swift +0 -52
  244. package/Sources/Runic/UsageProgressBar.swift +0 -228
  245. package/Sources/Runic/Utilities/DisplayLink.swift +0 -96
  246. package/Sources/Runic/Utilities/LoadingPattern.swift +0 -62
  247. package/Sources/Runic/Utilities/PerformanceConstants.swift +0 -85
  248. package/Sources/Runic/Views/Menu/AlertsMenuView.swift +0 -254
  249. package/Sources/Runic/Views/Menu/ChartPanelStyle.swift +0 -22
  250. package/Sources/Runic/Views/Menu/CostComparativeChartMenuView.swift +0 -275
  251. package/Sources/Runic/Views/Menu/CostHistoryChartMenuView.swift +0 -377
  252. package/Sources/Runic/Views/Menu/CreditsHistoryChartMenuView.swift +0 -312
  253. package/Sources/Runic/Views/Menu/EfficiencyMetricsMenuView.swift +0 -311
  254. package/Sources/Runic/Views/Menu/HeroStatCardsMenuView.swift +0 -231
  255. package/Sources/Runic/Views/Menu/HourlyActivityChartMenuView.swift +0 -228
  256. package/Sources/Runic/Views/Menu/InlineUsageChartView.swift +0 -157
  257. package/Sources/Runic/Views/Menu/MenuCardEntranceModifier.swift +0 -63
  258. package/Sources/Runic/Views/Menu/MenuCardSidebarView.swift +0 -248
  259. package/Sources/Runic/Views/Menu/MenuCardSkeletonView.swift +0 -104
  260. package/Sources/Runic/Views/Menu/MenuCardView.swift +0 -1889
  261. package/Sources/Runic/Views/Menu/MenuContent.swift +0 -153
  262. package/Sources/Runic/Views/Menu/MenuDescriptor.swift +0 -371
  263. package/Sources/Runic/Views/Menu/MenuHighlightStyle.swift +0 -35
  264. package/Sources/Runic/Views/Menu/ModelBreakdownMenuView.swift +0 -241
  265. package/Sources/Runic/Views/Menu/OverviewMenuView.swift +0 -281
  266. package/Sources/Runic/Views/Menu/ProjectBreakdownMenuView.swift +0 -214
  267. package/Sources/Runic/Views/Menu/ProjectBudgetMenuView.swift +0 -220
  268. package/Sources/Runic/Views/Menu/ProviderTabBarView.swift +0 -86
  269. package/Sources/Runic/Views/Menu/SubscriptionUtilizationChartMenuView.swift +0 -214
  270. package/Sources/Runic/Views/Menu/UsageBreakdownChartMenuView.swift +0 -398
  271. package/Sources/Runic/Views/Menu/UsageHeatmapMenuView.swift +0 -231
  272. package/Sources/Runic/Views/Menu/UsageTimelineChartMenuView.swift +0 -369
  273. package/Sources/Runic/Views/Menu/UsageWindowComparisonChartMenuView.swift +0 -191
  274. package/Sources/Runic/Views/Menu/WeeklyActivityChartMenuView.swift +0 -132
  275. package/Sources/Runic/Views/Performance/PerformanceDashboardView.swift +0 -621
  276. package/Sources/Runic/Views/Preferences/LiquidComponents.swift +0 -306
  277. package/Sources/Runic/Views/Preferences/PreferencesAboutPane.swift +0 -271
  278. package/Sources/Runic/Views/Preferences/PreferencesAdvancedPane.swift +0 -268
  279. package/Sources/Runic/Views/Preferences/PreferencesAlertsPane.swift +0 -418
  280. package/Sources/Runic/Views/Preferences/PreferencesAnalyticsPane.swift +0 -637
  281. package/Sources/Runic/Views/Preferences/PreferencesBudgetsPane.swift +0 -344
  282. package/Sources/Runic/Views/Preferences/PreferencesComponents.swift +0 -230
  283. package/Sources/Runic/Views/Preferences/PreferencesCustomProvidersPane.swift +0 -321
  284. package/Sources/Runic/Views/Preferences/PreferencesDebugPane.swift +0 -469
  285. package/Sources/Runic/Views/Preferences/PreferencesGeneralPane.swift +0 -250
  286. package/Sources/Runic/Views/Preferences/PreferencesHelpPane.swift +0 -50
  287. package/Sources/Runic/Views/Preferences/PreferencesIntegrationsPane.swift +0 -572
  288. package/Sources/Runic/Views/Preferences/PreferencesPerformancePane.swift +0 -291
  289. package/Sources/Runic/Views/Preferences/PreferencesProvidersPane.swift +0 -3480
  290. package/Sources/Runic/Views/Preferences/PreferencesSelection.swift +0 -29
  291. package/Sources/Runic/Views/Preferences/PreferencesSyncPane.swift +0 -61
  292. package/Sources/Runic/Views/Preferences/PreferencesView.swift +0 -213
  293. package/Sources/Runic/Views/Rating/QualityRatingView.swift +0 -238
  294. package/Sources/Runic/Views/Team/TeamDashboardView.swift +0 -376
  295. package/Sources/Runic/Views/Team/TeamInviteSheet.swift +0 -175
  296. package/Sources/Runic/Views/Team/TeamManagementView.swift +0 -762
  297. package/Sources/Runic/Views/Team/TeamMemberRow.swift +0 -181
  298. package/Sources/RunicCLI/CLIEntry.swift +0 -983
  299. package/Sources/RunicCLI/CLIRenderer.swift +0 -87
  300. package/Sources/RunicCLI/Commands/EnhancedUsageCommand.swift +0 -588
  301. package/Sources/RunicCLI/Commands/ModelsCommand.swift +0 -363
  302. package/Sources/RunicCLI/Commands/ProjectsCommand.swift +0 -453
  303. package/Sources/RunicCLI/Commands/ResetCommand.swift +0 -430
  304. package/Sources/RunicCLI/Commands/UsageLedgerSourceFactory.swift +0 -167
  305. package/Sources/RunicClaudeWatchdog/main.swift +0 -122
  306. package/Sources/RunicClaudeWebProbe/main.swift +0 -62
  307. package/Sources/RunicCore/AlertRuleStore.swift +0 -187
  308. package/Sources/RunicCore/BrowserCookieImportOrder.swift +0 -25
  309. package/Sources/RunicCore/CopilotUsageModels.swift +0 -84
  310. package/Sources/RunicCore/CostUsageFetcher.swift +0 -119
  311. package/Sources/RunicCore/CostUsageModels.swift +0 -479
  312. package/Sources/RunicCore/CreditsModels.swift +0 -50
  313. package/Sources/RunicCore/CustomProviders/CustomProviderModels.swift +0 -268
  314. package/Sources/RunicCore/CustomProviders/GenericProviderFetcher.swift +0 -631
  315. package/Sources/RunicCore/CustomProviders/ProviderTemplates.swift +0 -444
  316. package/Sources/RunicCore/Host/PTY/TTYCommandRunner.swift +0 -679
  317. package/Sources/RunicCore/Host/Process/SubprocessRunner.swift +0 -135
  318. package/Sources/RunicCore/Integrations/GitHubIntegration.swift +0 -173
  319. package/Sources/RunicCore/Logging/JSONStderrLogHandler.swift +0 -79
  320. package/Sources/RunicCore/Logging/OSLogLogHandler.swift +0 -86
  321. package/Sources/RunicCore/Logging/RunicLog.swift +0 -123
  322. package/Sources/RunicCore/Models/EnhancedUsageModels.swift +0 -370
  323. package/Sources/RunicCore/OpenAIDashboardModels.swift +0 -210
  324. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardBrowserCookieImporter.swift +0 -676
  325. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardFetcher.swift +0 -492
  326. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardNavigationDelegate.swift +0 -51
  327. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardParser.swift +0 -483
  328. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardScrapeScript.swift +0 -558
  329. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardWebViewCache.swift +0 -204
  330. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardWebsiteDataStore.swift +0 -78
  331. package/Sources/RunicCore/PathEnvironment.swift +0 -482
  332. package/Sources/RunicCore/Performance/PerformanceModels.swift +0 -371
  333. package/Sources/RunicCore/Performance/PerformanceStorageImpl.swift +0 -426
  334. package/Sources/RunicCore/Policy/UsagePolicyEngine.swift +0 -178
  335. package/Sources/RunicCore/ProjectBudgetStore.swift +0 -102
  336. package/Sources/RunicCore/ProviderCostSnapshot.swift +0 -29
  337. package/Sources/RunicCore/Providers/Antigravity/AntigravityProviderDescriptor.swift +0 -68
  338. package/Sources/RunicCore/Providers/Antigravity/AntigravityStatusProbe.swift +0 -685
  339. package/Sources/RunicCore/Providers/Auggie/AuggieProviderDescriptor.swift +0 -83
  340. package/Sources/RunicCore/Providers/Auggie/AuggieUsageFetcher.swift +0 -142
  341. package/Sources/RunicCore/Providers/Azure/AzureProviderDescriptor.swift +0 -141
  342. package/Sources/RunicCore/Providers/Azure/AzureUsageFetcher.swift +0 -188
  343. package/Sources/RunicCore/Providers/Bedrock/BedrockProviderDescriptor.swift +0 -126
  344. package/Sources/RunicCore/Providers/Bedrock/BedrockUsageFetcher.swift +0 -164
  345. package/Sources/RunicCore/Providers/Cerebras/CerebrasProviderDescriptor.swift +0 -84
  346. package/Sources/RunicCore/Providers/Cerebras/CerebrasUsageFetcher.swift +0 -75
  347. package/Sources/RunicCore/Providers/Claude/ClaudeCLISession.swift +0 -332
  348. package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthCredentials.swift +0 -180
  349. package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthUsageFetcher.swift +0 -137
  350. package/Sources/RunicCore/Providers/Claude/ClaudeProviderDescriptor.swift +0 -209
  351. package/Sources/RunicCore/Providers/Claude/ClaudeStatusProbe.swift +0 -654
  352. package/Sources/RunicCore/Providers/Claude/ClaudeUsageDataSource.swift +0 -30
  353. package/Sources/RunicCore/Providers/Claude/ClaudeUsageFetcher.swift +0 -480
  354. package/Sources/RunicCore/Providers/Claude/ClaudeWeb/ClaudeWebAPIFetcher.swift +0 -780
  355. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthCredentials.swift +0 -147
  356. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthUsageFetcher.swift +0 -280
  357. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexTokenRefresher.swift +0 -100
  358. package/Sources/RunicCore/Providers/Codex/CodexProviderDescriptor.swift +0 -245
  359. package/Sources/RunicCore/Providers/Codex/CodexStatusProbe.swift +0 -125
  360. package/Sources/RunicCore/Providers/Codex/CodexUsageDataSource.swift +0 -26
  361. package/Sources/RunicCore/Providers/Codex/CodexWebDashboardStrategy.swift +0 -183
  362. package/Sources/RunicCore/Providers/Cohere/CohereProviderDescriptor.swift +0 -83
  363. package/Sources/RunicCore/Providers/Cohere/CohereUsageFetcher.swift +0 -85
  364. package/Sources/RunicCore/Providers/Copilot/CopilotDeviceFlow.swift +0 -123
  365. package/Sources/RunicCore/Providers/Copilot/CopilotGitHubCLITokenReader.swift +0 -117
  366. package/Sources/RunicCore/Providers/Copilot/CopilotProviderDescriptor.swift +0 -100
  367. package/Sources/RunicCore/Providers/Copilot/CopilotUsageFetcher.swift +0 -293
  368. package/Sources/RunicCore/Providers/Copilot/CopilotVSCodeTokenReader.swift +0 -385
  369. package/Sources/RunicCore/Providers/Cursor/CursorProviderDescriptor.swift +0 -67
  370. package/Sources/RunicCore/Providers/Cursor/CursorStatusProbe.swift +0 -595
  371. package/Sources/RunicCore/Providers/DeepSeek/DeepSeekProviderDescriptor.swift +0 -85
  372. package/Sources/RunicCore/Providers/DeepSeek/DeepSeekUsageFetcher.swift +0 -108
  373. package/Sources/RunicCore/Providers/Factory/FactoryLocalStorageImporter.swift +0 -398
  374. package/Sources/RunicCore/Providers/Factory/FactoryProviderDescriptor.swift +0 -67
  375. package/Sources/RunicCore/Providers/Factory/FactoryStatusProbe.swift +0 -1276
  376. package/Sources/RunicCore/Providers/Fireworks/FireworksProviderDescriptor.swift +0 -84
  377. package/Sources/RunicCore/Providers/Fireworks/FireworksUsageFetcher.swift +0 -75
  378. package/Sources/RunicCore/Providers/Gemini/GeminiProviderDescriptor.swift +0 -67
  379. package/Sources/RunicCore/Providers/Gemini/GeminiStatusProbe.swift +0 -839
  380. package/Sources/RunicCore/Providers/Groq/GroqProviderDescriptor.swift +0 -83
  381. package/Sources/RunicCore/Providers/Groq/GroqUsageFetcher.swift +0 -71
  382. package/Sources/RunicCore/Providers/Kimi/KimiProviderDescriptor.swift +0 -83
  383. package/Sources/RunicCore/Providers/Kimi/KimiUsageFetcher.swift +0 -77
  384. package/Sources/RunicCore/Providers/MiniMax/MiniMaxProviderDescriptor.swift +0 -97
  385. package/Sources/RunicCore/Providers/MiniMax/MiniMaxSettingsReader.swift +0 -54
  386. package/Sources/RunicCore/Providers/MiniMax/MiniMaxUsageFetcher.swift +0 -168
  387. package/Sources/RunicCore/Providers/MiniMax/MiniMaxWebUsageFetcher.swift +0 -911
  388. package/Sources/RunicCore/Providers/Mistral/MistralProviderDescriptor.swift +0 -84
  389. package/Sources/RunicCore/Providers/Mistral/MistralUsageFetcher.swift +0 -75
  390. package/Sources/RunicCore/Providers/OpenRouter/OpenRouterProviderDescriptor.swift +0 -87
  391. package/Sources/RunicCore/Providers/OpenRouter/OpenRouterUsageFetcher.swift +0 -216
  392. package/Sources/RunicCore/Providers/Perplexity/PerplexityProviderDescriptor.swift +0 -84
  393. package/Sources/RunicCore/Providers/Perplexity/PerplexityUsageFetcher.swift +0 -75
  394. package/Sources/RunicCore/Providers/ProviderBranding.swift +0 -25
  395. package/Sources/RunicCore/Providers/ProviderCLIConfig.swift +0 -17
  396. package/Sources/RunicCore/Providers/ProviderDescriptor.swift +0 -129
  397. package/Sources/RunicCore/Providers/ProviderFetchPlan.swift +0 -263
  398. package/Sources/RunicCore/Providers/ProviderSettingsSnapshot.swift +0 -98
  399. package/Sources/RunicCore/Providers/ProviderTokenResolver.swift +0 -501
  400. package/Sources/RunicCore/Providers/ProviderVersionDetector.swift +0 -68
  401. package/Sources/RunicCore/Providers/Providers.swift +0 -184
  402. package/Sources/RunicCore/Providers/Qwen/QwenProviderDescriptor.swift +0 -86
  403. package/Sources/RunicCore/Providers/Qwen/QwenSettingsReader.swift +0 -30
  404. package/Sources/RunicCore/Providers/Qwen/QwenUsageStats.swift +0 -328
  405. package/Sources/RunicCore/Providers/SambaNova/SambaNovaProviderDescriptor.swift +0 -84
  406. package/Sources/RunicCore/Providers/SambaNova/SambaNovaUsageFetcher.swift +0 -75
  407. package/Sources/RunicCore/Providers/Together/TogetherProviderDescriptor.swift +0 -83
  408. package/Sources/RunicCore/Providers/Together/TogetherUsageFetcher.swift +0 -75
  409. package/Sources/RunicCore/Providers/VertexAI/VertexAIProviderDescriptor.swift +0 -123
  410. package/Sources/RunicCore/Providers/VertexAI/VertexAISettingsReader.swift +0 -48
  411. package/Sources/RunicCore/Providers/VertexAI/VertexAIUsageFetcher.swift +0 -144
  412. package/Sources/RunicCore/Providers/XAI/XAIProviderDescriptor.swift +0 -83
  413. package/Sources/RunicCore/Providers/XAI/XAIUsageFetcher.swift +0 -75
  414. package/Sources/RunicCore/Providers/Zai/ZaiProviderDescriptor.swift +0 -74
  415. package/Sources/RunicCore/Providers/Zai/ZaiSettingsReader.swift +0 -41
  416. package/Sources/RunicCore/Providers/Zai/ZaiUsageStats.swift +0 -745
  417. package/Sources/RunicCore/Sync/BackgroundSyncManager.swift +0 -384
  418. package/Sources/RunicCore/Sync/SyncConflictResolver.swift +0 -307
  419. package/Sources/RunicCore/Sync/SyncProtocol.swift +0 -287
  420. package/Sources/RunicCore/Sync/SyncRecord.swift +0 -402
  421. package/Sources/RunicCore/Sync/SyncUsageExample.swift +0 -288
  422. package/Sources/RunicCore/Sync/TeamSyncRecords.swift +0 -768
  423. package/Sources/RunicCore/Sync/iCloudSyncEngine.swift +0 -338
  424. package/Sources/RunicCore/Team/TeamModels.swift +0 -584
  425. package/Sources/RunicCore/Team/TeamShowbackExporter.swift +0 -495
  426. package/Sources/RunicCore/Team/TeamStore.swift +0 -809
  427. package/Sources/RunicCore/TextParsing.swift +0 -55
  428. package/Sources/RunicCore/UsageFetcher.swift +0 -694
  429. package/Sources/RunicCore/UsageFormatter.swift +0 -410
  430. package/Sources/RunicCore/UsageLedger/ClaudeUsageLogSource.swift +0 -441
  431. package/Sources/RunicCore/UsageLedger/CodexUsageLogSource.swift +0 -502
  432. package/Sources/RunicCore/UsageLedger/LedgerCache.swift +0 -161
  433. package/Sources/RunicCore/UsageLedger/OTelGenAILedgerAdapter.swift +0 -550
  434. package/Sources/RunicCore/UsageLedger/UsageLedger.swift +0 -29
  435. package/Sources/RunicCore/UsageLedger/UsageLedgerAggregator.swift +0 -675
  436. package/Sources/RunicCore/UsageLedger/UsageLedgerInsightsAdvisor.swift +0 -209
  437. package/Sources/RunicCore/UsageLedger/UsageLedgerModels.swift +0 -417
  438. package/Sources/RunicCore/UsageLedger/UsageLedgerProjectIdentity.swift +0 -284
  439. package/Sources/RunicCore/UsagePace.swift +0 -81
  440. package/Sources/RunicCore/Vendored/CostUsage/CostUsageCache.swift +0 -73
  441. package/Sources/RunicCore/Vendored/CostUsage/CostUsageJsonl.swift +0 -74
  442. package/Sources/RunicCore/Vendored/CostUsage/CostUsagePricing.swift +0 -208
  443. package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner+Claude.swift +0 -455
  444. package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner+Timestamp.swift +0 -132
  445. package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner.swift +0 -589
  446. package/Sources/RunicCore/WidgetSnapshot.swift +0 -183
  447. package/Sources/RunicMacroSupport/ProviderRegistrationMacros.swift +0 -14
  448. package/Sources/RunicMacros/ProviderRegistrationMacros.swift +0 -216
  449. package/Sources/RunicWidget/RunicWidgetBundle.swift +0 -79
  450. package/Sources/RunicWidget/RunicWidgetProvider.swift +0 -283
  451. package/Sources/RunicWidget/RunicWidgetViews.swift +0 -680
  452. package/Tests/RunicTests/AntigravityStatusProbeTests.swift +0 -50
  453. package/Tests/RunicTests/AppDelegateTests.swift +0 -48
  454. package/Tests/RunicTests/BrowserCookieOrderLabelTests.swift +0 -21
  455. package/Tests/RunicTests/CLIArgumentParsingTests.swift +0 -69
  456. package/Tests/RunicTests/CLICostTests.swift +0 -64
  457. package/Tests/RunicTests/CLIProviderSelectionTests.swift +0 -21
  458. package/Tests/RunicTests/CLISnapshotTests.swift +0 -71
  459. package/Tests/RunicTests/CLIWebFallbackTests.swift +0 -57
  460. package/Tests/RunicTests/ClaudeOAuthTests.swift +0 -163
  461. package/Tests/RunicTests/ClaudeResilienceTests.swift +0 -29
  462. package/Tests/RunicTests/ClaudeUsageTests.swift +0 -369
  463. package/Tests/RunicTests/CodexOAuthTests.swift +0 -121
  464. package/Tests/RunicTests/CodexUsageLogSourceTests.swift +0 -80
  465. package/Tests/RunicTests/CopilotTokenResolverTests.swift +0 -74
  466. package/Tests/RunicTests/CopilotVSCodeTokenReaderTests.swift +0 -74
  467. package/Tests/RunicTests/CostUsageDecodingTests.swift +0 -392
  468. package/Tests/RunicTests/CostUsagePricingTests.swift +0 -48
  469. package/Tests/RunicTests/CostUsageScannerTests.swift +0 -698
  470. package/Tests/RunicTests/CursorStatusProbeTests.swift +0 -322
  471. package/Tests/RunicTests/FactoryStatusProbeTests.swift +0 -67
  472. package/Tests/RunicTests/GeminiAPITestHelpers.swift +0 -94
  473. package/Tests/RunicTests/GeminiLoginAlertTests.swift +0 -27
  474. package/Tests/RunicTests/GeminiStatusProbeAPITests.swift +0 -283
  475. package/Tests/RunicTests/GeminiStatusProbePlanTests.swift +0 -279
  476. package/Tests/RunicTests/GeminiStatusProbeTests.swift +0 -232
  477. package/Tests/RunicTests/GeminiTestEnvironment.swift +0 -87
  478. package/Tests/RunicTests/GoogleWorkspaceStatusTests.swift +0 -72
  479. package/Tests/RunicTests/InstallOriginTests.swift +0 -17
  480. package/Tests/RunicTests/KeyboardShortcutsBundleTests.swift +0 -9
  481. package/Tests/RunicTests/LiveAccountTests.swift +0 -24
  482. package/Tests/RunicTests/LoadingPatternTests.swift +0 -34
  483. package/Tests/RunicTests/MenuCardModelTests.swift +0 -544
  484. package/Tests/RunicTests/MiniMaxCookieHeaderStoreTestSupport.swift +0 -11
  485. package/Tests/RunicTests/MiniMaxGroupIDStoreTestSupport.swift +0 -11
  486. package/Tests/RunicTests/MiniMaxParsingTests.swift +0 -67
  487. package/Tests/RunicTests/MiniMaxTokenStoreTestSupport.swift +0 -11
  488. package/Tests/RunicTests/OTelGenAILedgerAdapterTests.swift +0 -110
  489. package/Tests/RunicTests/OpenAIDashboardBrowserCookieImporterTests.swift +0 -16
  490. package/Tests/RunicTests/OpenAIDashboardFetcherCreditsWaitTests.swift +0 -74
  491. package/Tests/RunicTests/OpenAIDashboardOffscreenHostTests.swift +0 -26
  492. package/Tests/RunicTests/OpenAIDashboardParserTests.swift +0 -133
  493. package/Tests/RunicTests/OpenAIWebAccountSwitchTests.swift +0 -64
  494. package/Tests/RunicTests/OpenRouterTokenStoreTestSupport.swift +0 -131
  495. package/Tests/RunicTests/PathBuilderTests.swift +0 -236
  496. package/Tests/RunicTests/ProviderFetchPipelineTests.swift +0 -159
  497. package/Tests/RunicTests/ProviderIconResourcesTests.swift +0 -37
  498. package/Tests/RunicTests/ProviderMetadataStatusLinkTests.swift +0 -15
  499. package/Tests/RunicTests/ProviderRegistryTests.swift +0 -29
  500. package/Tests/RunicTests/ProviderSettingsDescriptorTests.swift +0 -236
  501. package/Tests/RunicTests/ProviderToggleStoreTests.swift +0 -50
  502. package/Tests/RunicTests/RunicTests.swift +0 -119
  503. package/Tests/RunicTests/SessionQuotaNotificationLogicTests.swift +0 -35
  504. package/Tests/RunicTests/SettingsStoreTests.swift +0 -265
  505. package/Tests/RunicTests/StatusItemAnimationTests.swift +0 -54
  506. package/Tests/RunicTests/StatusMenuTests.swift +0 -475
  507. package/Tests/RunicTests/StatusProbeTests.swift +0 -376
  508. package/Tests/RunicTests/SubprocessRunnerTests.swift +0 -18
  509. package/Tests/RunicTests/SubscriptionDetectionTests.swift +0 -64
  510. package/Tests/RunicTests/TTYCommandRunnerTests.swift +0 -147
  511. package/Tests/RunicTests/TTYIntegrationTests.swift +0 -41
  512. package/Tests/RunicTests/TeamShowbackExporterTests.swift +0 -157
  513. package/Tests/RunicTests/TextParsingTests.swift +0 -11
  514. package/Tests/RunicTests/UsageFormatterTests.swift +0 -111
  515. package/Tests/RunicTests/UsageLedgerAnomalyDetectionTests.swift +0 -170
  516. package/Tests/RunicTests/UsageLedgerForecastTests.swift +0 -211
  517. package/Tests/RunicTests/UsageLedgerInsightsAdvisorTests.swift +0 -81
  518. package/Tests/RunicTests/UsageLedgerProjectNameTests.swift +0 -168
  519. package/Tests/RunicTests/UsagePaceTests.swift +0 -76
  520. package/Tests/RunicTests/UsagePaceTextTests.swift +0 -108
  521. package/Tests/RunicTests/UsagePolicyEngineTests.swift +0 -89
  522. package/Tests/RunicTests/WidgetSnapshotTests.swift +0 -43
  523. package/Tests/RunicTests/ZaiProviderTests.swift +0 -59
  524. package/Tests/RunicTests/ZaiTokenStoreTestSupport.swift +0 -9
  525. package/TestsLinux/PlatformGatingTests.swift +0 -46
  526. package/appcast.xml +0 -104
  527. package/assets/logo-concept-stack.svg +0 -24
  528. package/assets/logo-minimal-bars.svg +0 -15
  529. package/assets/logo.svg +0 -20
  530. package/assets/logo2.svg +0 -43
  531. package/bin/docs-list +0 -5
  532. package/build-and-run.sh +0 -369
  533. package/docs/.nojekyll +0 -1
  534. package/docs/CNAME +0 -1
  535. package/docs/antigravity.md +0 -75
  536. package/docs/architecture.md +0 -32
  537. package/docs/claude.md +0 -93
  538. package/docs/cli-commands/integration_guide.md +0 -371
  539. package/docs/cli-commands/quick_reference.md +0 -362
  540. package/docs/cli-commands/readme.md +0 -361
  541. package/docs/cli.md +0 -156
  542. package/docs/cloudkit_sync_guide.md +0 -495
  543. package/docs/codebase_review.md +0 -288
  544. package/docs/codex-oauth.md +0 -635
  545. package/docs/codex.md +0 -104
  546. package/docs/codexbar.png +0 -0
  547. package/docs/copilot.md +0 -44
  548. package/docs/cursor.md +0 -46
  549. package/docs/design/designcomparisonchart.md +0 -510
  550. package/docs/design/implementationguide.md +0 -792
  551. package/docs/design/menubaricondesignconcepts.md +0 -796
  552. package/docs/design/mockups/hybridiconconcept.svg +0 -62
  553. package/docs/design/mockups/infinityiconconcept.svg +0 -41
  554. package/docs/design/mockups/infinityiconstates.svg +0 -129
  555. package/docs/design/mockups/wavelogorefined.svg +0 -48
  556. package/docs/design/quick_summary.md +0 -426
  557. package/docs/design/readme.md +0 -478
  558. package/docs/design/sizespecifications.md +0 -575
  559. package/docs/design-system.md +0 -836
  560. package/docs/factory.md +0 -103
  561. package/docs/gemini.md +0 -73
  562. package/docs/icon.md +0 -37
  563. package/docs/icon.png +0 -0
  564. package/docs/index.html +0 -175
  565. package/docs/keychain_fix.md +0 -274
  566. package/docs/minimax.md +0 -71
  567. package/docs/packaging.md +0 -25
  568. package/docs/progress-bar-improvements.md +0 -240
  569. package/docs/progress-bar-quick-reference.md +0 -283
  570. package/docs/progress-bar-technical-details.md +0 -432
  571. package/docs/progress-bar-visual-test.swift +0 -375
  572. package/docs/provider.md +0 -202
  573. package/docs/providers.md +0 -86
  574. package/docs/refactor/macros.md +0 -35
  575. package/docs/refresh-loop.md +0 -22
  576. package/docs/releasing-homebrew.md +0 -35
  577. package/docs/releasing.md +0 -121
  578. package/docs/research/concrete_todo_2026-02-22.md +0 -47
  579. package/docs/research/core-feature-research.md +0 -248
  580. package/docs/research/feature_uiux_roadmap_2026-02-22.md +0 -202
  581. package/docs/research/parity_matrix.md +0 -49
  582. package/docs/research/provider_expansion_candidates_2026-02-22.md +0 -80
  583. package/docs/research/provider_model_token_project_matrix_2026-02-23.md +0 -46
  584. package/docs/research/release_gate_checklist.md +0 -57
  585. package/docs/site.css +0 -505
  586. package/docs/sparkle.md +0 -28
  587. package/docs/status.md +0 -28
  588. package/docs/sync/implementation.md +0 -393
  589. package/docs/sync/readme.md +0 -317
  590. package/docs/sync_files_summary.md +0 -391
  591. package/docs/sync_quick_reference.md +0 -225
  592. package/docs/todo.md +0 -11
  593. package/docs/ui.md +0 -29
  594. package/docs/web-integration.md +0 -9
  595. package/docs/widgets.md +0 -85
  596. package/docs/workflows/error-handling-improvements.md +0 -434
  597. package/docs/workflows/folder_structure.md +0 -299
  598. package/docs/workflows/loading_states.md +0 -446
  599. package/docs/workflows/loading_states_examples.md +0 -565
  600. package/docs/workflows/loading_states_flow.md +0 -430
  601. package/docs/workflows/performance_optimizations.md +0 -457
  602. package/docs/workflows/phase1-cli-testing-report.md +0 -313
  603. package/docs/workflows/quick_reference.md +0 -228
  604. package/docs/workflows/readme.md +0 -59
  605. package/docs/workflows/recent_improvements.md +0 -275
  606. package/docs/workflows/sync_enablement_summary.md +0 -400
  607. package/docs/zai.md +0 -43
  608. package/runic.png +0 -0
  609. package/runic.svg +0 -15
  610. package/version.env +0 -2
@@ -1,1222 +0,0 @@
1
- import AppKit
2
- import RunicCore
3
-
4
- // **IconRenderer** - Generates menubar status item icons with usage visualization
5
- //
6
- // **Purpose:**
7
- // Creates pixel-perfect 18×18pt (36×36px @2x) template images for the macOS menubar.
8
- // Renders usage bars, stale indicators, and provider status into the icon.
9
- //
10
- // **Responsibilities:**
11
- // - Generate icons showing session/weekly usage patterns
12
- // - Apply stale data dimming when data is > 5 minutes old
13
- // - Cache rendered icons for performance (64 icon cache, 512 morph cache)
14
- // - Support template (adapts to menubar theme) and vibrant appearances
15
- // - Render loading animations and error states
16
- //
17
- // **Performance:**
18
- // - **O(1) icon cache lookup** via IconCacheKey hash
19
- // - **O(1) morph cache** for animation frames
20
- // - Cap cache sizes via `PerformanceConstants`
21
- // - All rendering happens off main thread in `dispatchPrecondition(condition: .notOnQueue(.main))`
22
- //
23
- // **Dependencies:**
24
- // - `PerformanceConstants` - Cache sizes and timing
25
- // - `UsageProvider` - Provider-specific rendering
26
- // - `AppKit/CoreGraphics` - Image generation
27
- //
28
- // **Usage:**
29
- // ```swift
30
- // let icon = IconRenderer.render(
31
- // state: .usage(snap, status),
32
- // indicator: .none,
33
- // appearance: .template,
34
- // dataMode: .remaining
35
- // )
36
- // statusItem.button?.image = icon
37
- // ```
38
-
39
- enum IconAppearance {
40
- case template // Adapts to menubar theme (light/dark mode)
41
- case vibrant // Full color rendering
42
- }
43
-
44
- enum IconDataMode {
45
- case remaining // Show remaining quota
46
- case used // Show used quota
47
- }
48
-
49
- enum IconRenderer {
50
- private static let creditsCap: Double = 1000
51
- private static let baseSize = NSSize(width: 38, height: 22)
52
- // Render to a 38×22 pt template (76×44 px at 2×) for better visibility.
53
- private static let outputSize = NSSize(width: 38, height: 22)
54
- private static let outputScale: CGFloat = 2
55
- private static let canvasPx = Int(outputSize.width * outputScale)
56
-
57
- /// Infinity symbol base template - loaded lazily from Resources
58
- private static let waveLogoTemplate: NSImage? = {
59
- guard let url = Bundle.main.url(forResource: "RunicMenubarIcon", withExtension: "svg"),
60
- let image = NSImage(contentsOf: url)
61
- else {
62
- return nil
63
- }
64
- return image
65
- }()
66
-
67
- private struct PixelGrid {
68
- let scale: CGFloat
69
-
70
- func pt(_ px: Int) -> CGFloat {
71
- CGFloat(px) / self.scale
72
- }
73
-
74
- func rect(x: Int, y: Int, w: Int, h: Int) -> CGRect {
75
- CGRect(x: self.pt(x), y: self.pt(y), width: self.pt(w), height: self.pt(h))
76
- }
77
-
78
- func snapDelta(_ value: CGFloat) -> CGFloat {
79
- (value * self.scale).rounded() / self.scale
80
- }
81
- }
82
-
83
- private static let grid = PixelGrid(scale: outputScale)
84
-
85
- private struct IconCacheKey: Hashable {
86
- let primary: Int
87
- let weekly: Int
88
- let credits: Int
89
- let stale: Bool
90
- let style: Int
91
- let indicator: Int
92
- let appearance: Int
93
- let dataMode: Int
94
- }
95
-
96
- private final class IconCacheStore: @unchecked Sendable {
97
- private var cache: [IconCacheKey: NSImage] = [:]
98
- private var order: [IconCacheKey] = []
99
- private let lock = NSLock()
100
-
101
- func cachedIcon(for key: IconCacheKey) -> NSImage? {
102
- self.lock.lock()
103
- defer { self.lock.unlock() }
104
- guard let image = self.cache[key] else { return nil }
105
- if let idx = self.order.firstIndex(of: key) {
106
- self.order.remove(at: idx)
107
- self.order.append(key)
108
- }
109
- return image
110
- }
111
-
112
- func storeIcon(_ image: NSImage, for key: IconCacheKey, limit: Int) {
113
- self.lock.lock()
114
- defer { self.lock.unlock() }
115
- self.cache[key] = image
116
- self.order.removeAll { $0 == key }
117
- self.order.append(key)
118
- while self.order.count > limit {
119
- let oldest = self.order.removeFirst()
120
- self.cache.removeValue(forKey: oldest)
121
- }
122
- }
123
- }
124
-
125
- private static let iconCacheStore = IconCacheStore()
126
- private static let iconCacheLimit = PerformanceConstants.iconCacheSize
127
- private static let morphBucketCount = 200
128
- private static let morphCache = MorphCache(limit: PerformanceConstants.morphCacheSize)
129
-
130
- private final class MorphCache: @unchecked Sendable {
131
- private let cache = NSCache<NSNumber, NSImage>()
132
-
133
- init(limit: Int) {
134
- self.cache.countLimit = limit
135
- }
136
-
137
- func image(for key: NSNumber) -> NSImage? {
138
- self.cache.object(forKey: key)
139
- }
140
-
141
- func set(_ image: NSImage, for key: NSNumber) {
142
- self.cache.setObject(image, forKey: key)
143
- }
144
- }
145
-
146
- private struct RectPx: Hashable {
147
- let x: Int
148
- let y: Int
149
- let w: Int
150
- let h: Int
151
-
152
- var midXPx: Int {
153
- self.x + self.w / 2
154
- }
155
-
156
- var midYPx: Int {
157
- self.y + self.h / 2
158
- }
159
-
160
- func rect() -> CGRect {
161
- Self.grid.rect(x: self.x, y: self.y, w: self.w, h: self.h)
162
- }
163
-
164
- private static let grid = IconRenderer.grid
165
- }
166
-
167
- private enum SigilStyle {
168
- case codex
169
- case claude
170
- case gemini
171
- case antigravity
172
- case cursor
173
- case factory
174
- case copilot
175
- case minimax
176
- case openrouter
177
- case groq
178
- case deepseek
179
- case fireworks
180
- case mistral
181
- case perplexity
182
- case kimi
183
- case auggie
184
- case together
185
- case cohere
186
- case xai
187
- case cerebras
188
- case sambanova
189
- case azure
190
- case bedrock
191
- case vertexai
192
- case zai
193
- case qwen
194
- case combined
195
- }
196
-
197
- // swiftlint:disable function_body_length
198
- static func makeIcon(
199
- primaryRemaining: Double?,
200
- weeklyRemaining: Double?,
201
- creditsRemaining: Double?,
202
- stale: Bool,
203
- style: IconStyle,
204
- blink: CGFloat = 0,
205
- wiggle: CGFloat = 0,
206
- tilt: CGFloat = 0,
207
- statusIndicator: ProviderStatusIndicator = .none,
208
- appearance: IconAppearance = .template,
209
- dataMode: IconDataMode = .remaining) -> NSImage
210
- {
211
- let shouldCache = blink <= 0.0001 && wiggle <= 0.0001 && tilt <= 0.0001
212
- let render = {
213
- self.renderImage(isTemplate: appearance == .template) {
214
- let topValue = primaryRemaining
215
- let bottomValue = weeklyRemaining
216
- let creditsRatio = creditsRemaining.map { min($0 / Self.creditsCap * 100, 100) }
217
- let pressure = Self.usagePressure(
218
- primary: topValue,
219
- weekly: bottomValue,
220
- credits: creditsRatio,
221
- dataMode: dataMode)
222
- let accentColor = Self.vibrantAccentColor(pressure: pressure, stale: stale)
223
- let baseColor = appearance == .template ? NSColor.labelColor : accentColor
224
-
225
- // Disable blink effect to prevent flicker
226
- let opacityMultiplier = 1.0
227
-
228
- let fillColor = baseColor.withAlphaComponent((stale ? 0.55 : 1.0) * opacityMultiplier)
229
- let baseAlpha: CGFloat = (stale ? 0.18 : (appearance == .template ? 0.28 : 0.38)) * opacityMultiplier
230
-
231
- let fillPercent = Self.iconFillPercent(
232
- primary: topValue,
233
- weekly: bottomValue,
234
- credits: creditsRatio,
235
- dataMode: dataMode)
236
-
237
- Self.drawWaveLogo(
238
- fillPercent: fillPercent,
239
- baseColor: baseColor.withAlphaComponent(baseAlpha),
240
- fillColor: fillColor)
241
-
242
- let overlayColor = appearance == .template
243
- ? NSColor.labelColor
244
- : NSColor.white.withAlphaComponent(0.92)
245
- Self.drawStatusOverlay(indicator: statusIndicator, color: overlayColor)
246
- }
247
- }
248
-
249
- if shouldCache {
250
- let key = IconCacheKey(
251
- primary: self.quantizedPercent(primaryRemaining),
252
- weekly: self.quantizedPercent(weeklyRemaining),
253
- credits: self.quantizedCredits(creditsRemaining),
254
- stale: stale,
255
- style: self.styleKey(style),
256
- indicator: self.indicatorKey(statusIndicator),
257
- appearance: self.appearanceKey(appearance),
258
- dataMode: self.dataModeKey(dataMode))
259
- if let cached = self.cachedIcon(for: key) {
260
- return cached
261
- }
262
- let image = render()
263
- self.storeIcon(image, for: key)
264
- return image
265
- }
266
-
267
- return render()
268
- }
269
-
270
- // swiftlint:enable function_body_length
271
-
272
- private static func sigilStyle(for style: IconStyle) -> SigilStyle {
273
- switch style {
274
- case .codex: .codex
275
- case .claude: .claude
276
- case .zai: .zai
277
- case .gemini: .gemini
278
- case .antigravity: .antigravity
279
- case .cursor: .cursor
280
- case .factory: .factory
281
- case .copilot: .copilot
282
- case .minimax: .minimax
283
- case .openrouter: .openrouter
284
- case .groq: .groq
285
- case .deepseek: .deepseek
286
- case .fireworks: .fireworks
287
- case .mistral: .mistral
288
- case .perplexity: .perplexity
289
- case .kimi: .kimi
290
- case .auggie: .auggie
291
- case .together: .together
292
- case .cohere: .cohere
293
- case .xai: .xai
294
- case .cerebras: .cerebras
295
- case .sambanova: .sambanova
296
- case .azure: .azure
297
- case .bedrock: .bedrock
298
- case .vertexai: .vertexai
299
- case .qwen: .qwen
300
- case .combined: .combined
301
- }
302
- }
303
-
304
- private static func chamferedPath(rectPx: RectPx, chamferPx: Int) -> NSBezierPath {
305
- let rect = rectPx.rect()
306
- let chamfer = Self.grid.pt(chamferPx)
307
- let x = rect.minX
308
- let y = rect.minY
309
- let w = rect.width
310
- let h = rect.height
311
- let path = NSBezierPath()
312
- path.move(to: NSPoint(x: x + chamfer, y: y))
313
- path.line(to: NSPoint(x: x + w - chamfer, y: y))
314
- path.line(to: NSPoint(x: x + w, y: y + chamfer))
315
- path.line(to: NSPoint(x: x + w, y: y + h - chamfer))
316
- path.line(to: NSPoint(x: x + w - chamfer, y: y + h))
317
- path.line(to: NSPoint(x: x + chamfer, y: y + h))
318
- path.line(to: NSPoint(x: x, y: y + h - chamfer))
319
- path.line(to: NSPoint(x: x, y: y + chamfer))
320
- path.close()
321
- return path
322
- }
323
-
324
- private static func drawSigil(_ style: SigilStyle, in rectPx: RectPx) {
325
- guard let ctx = NSGraphicsContext.current?.cgContext else { return }
326
- let centerXPx = rectPx.midXPx
327
- let centerYPx = rectPx.y + rectPx.h / 2
328
-
329
- func point(x: Int, y: Int) -> NSPoint {
330
- NSPoint(x: Self.grid.pt(x), y: Self.grid.pt(y))
331
- }
332
-
333
- ctx.saveGState()
334
- ctx.setBlendMode(.clear)
335
- ctx.setShouldAntialias(true)
336
-
337
- switch style {
338
- case .codex:
339
- let eyeSizePx = 3
340
- let eyeOffsetPx = 5
341
- let leftEye = Self.grid.rect(
342
- x: centerXPx - eyeOffsetPx - eyeSizePx / 2,
343
- y: centerYPx - eyeSizePx / 2,
344
- w: eyeSizePx,
345
- h: eyeSizePx)
346
- let rightEye = Self.grid.rect(
347
- x: centerXPx + eyeOffsetPx - eyeSizePx / 2,
348
- y: centerYPx - eyeSizePx / 2,
349
- w: eyeSizePx,
350
- h: eyeSizePx)
351
- NSBezierPath(rect: leftEye).fill()
352
- NSBezierPath(rect: rightEye).fill()
353
- case .claude:
354
- let slitWidthPx = 2
355
- let slitHeightPx = 6
356
- let slitOffsetPx = 5
357
- let leftSlit = Self.grid.rect(
358
- x: centerXPx - slitOffsetPx - slitWidthPx / 2,
359
- y: centerYPx - slitHeightPx / 2,
360
- w: slitWidthPx,
361
- h: slitHeightPx)
362
- let rightSlit = Self.grid.rect(
363
- x: centerXPx + slitOffsetPx - slitWidthPx / 2,
364
- y: centerYPx - slitHeightPx / 2,
365
- w: slitWidthPx,
366
- h: slitHeightPx)
367
- NSBezierPath(rect: leftSlit).fill()
368
- NSBezierPath(rect: rightSlit).fill()
369
- case .gemini:
370
- let diamondRadiusPx = 4
371
- let cx = Self.grid.pt(centerXPx)
372
- let cy = Self.grid.pt(centerYPx)
373
- let r = Self.grid.pt(diamondRadiusPx)
374
- let path = NSBezierPath()
375
- path.move(to: NSPoint(x: cx, y: cy + r))
376
- path.line(to: NSPoint(x: cx + r, y: cy))
377
- path.line(to: NSPoint(x: cx, y: cy - r))
378
- path.line(to: NSPoint(x: cx - r, y: cy))
379
- path.close()
380
- path.fill()
381
- case .antigravity:
382
- let dotSizePx = 4
383
- let dotRect = Self.grid.rect(
384
- x: centerXPx - dotSizePx / 2,
385
- y: rectPx.y + rectPx.h - dotSizePx - 1,
386
- w: dotSizePx,
387
- h: dotSizePx)
388
- NSBezierPath(ovalIn: dotRect).fill()
389
- case .cursor:
390
- let tipPx = 6
391
- let baseXPx = centerXPx + 4
392
- let path = NSBezierPath()
393
- path.move(to: point(x: baseXPx, y: centerYPx))
394
- path.line(to: point(x: baseXPx - tipPx, y: centerYPx + tipPx / 2))
395
- path.line(to: point(x: baseXPx - tipPx, y: centerYPx - tipPx / 2))
396
- path.close()
397
- path.fill()
398
- case .factory:
399
- let armPx = 6
400
- let thicknessPx = 2
401
- let vertical = Self.grid.rect(
402
- x: centerXPx - thicknessPx / 2,
403
- y: centerYPx - armPx / 2,
404
- w: thicknessPx,
405
- h: armPx)
406
- let horizontal = Self.grid.rect(
407
- x: centerXPx - armPx / 2,
408
- y: centerYPx - thicknessPx / 2,
409
- w: armPx,
410
- h: thicknessPx)
411
- NSBezierPath(rect: vertical).fill()
412
- NSBezierPath(rect: horizontal).fill()
413
- case .copilot:
414
- let eyeRadiusPx = 3
415
- let eyeOffsetPx = 4
416
- let leftEye = Self.grid.rect(
417
- x: centerXPx - eyeOffsetPx - eyeRadiusPx,
418
- y: centerYPx - eyeRadiusPx,
419
- w: eyeRadiusPx * 2,
420
- h: eyeRadiusPx * 2)
421
- let rightEye = Self.grid.rect(
422
- x: centerXPx + eyeOffsetPx - eyeRadiusPx,
423
- y: centerYPx - eyeRadiusPx,
424
- w: eyeRadiusPx * 2,
425
- h: eyeRadiusPx * 2)
426
- let bridge = Self.grid.rect(
427
- x: centerXPx - 2,
428
- y: centerYPx - 1,
429
- w: 4,
430
- h: 2)
431
- NSBezierPath(ovalIn: leftEye).fill()
432
- NSBezierPath(ovalIn: rightEye).fill()
433
- NSBezierPath(rect: bridge).fill()
434
- case .minimax:
435
- let triWidthPx = 6
436
- let triHeightPx = 5
437
- let leftCx = centerXPx - 4
438
- let rightCx = centerXPx + 4
439
- let leftPath = NSBezierPath()
440
- leftPath.move(to: point(x: leftCx, y: centerYPx + triHeightPx / 2))
441
- leftPath.line(to: point(x: leftCx - triWidthPx / 2, y: centerYPx - triHeightPx / 2))
442
- leftPath.line(to: point(x: leftCx + triWidthPx / 2, y: centerYPx - triHeightPx / 2))
443
- leftPath.close()
444
- let rightPath = NSBezierPath()
445
- rightPath.move(to: point(x: rightCx, y: centerYPx + triHeightPx / 2))
446
- rightPath.line(to: point(x: rightCx - triWidthPx / 2, y: centerYPx - triHeightPx / 2))
447
- rightPath.line(to: point(x: rightCx + triWidthPx / 2, y: centerYPx - triHeightPx / 2))
448
- rightPath.close()
449
- leftPath.fill()
450
- rightPath.fill()
451
- case .openrouter:
452
- let outerRadiusPx = 4
453
- let innerRadiusPx = 2
454
- let outerRect = Self.grid.rect(
455
- x: centerXPx - outerRadiusPx,
456
- y: centerYPx - outerRadiusPx,
457
- w: outerRadiusPx * 2,
458
- h: outerRadiusPx * 2)
459
- let innerRect = Self.grid.rect(
460
- x: centerXPx - innerRadiusPx,
461
- y: centerYPx - innerRadiusPx,
462
- w: innerRadiusPx * 2,
463
- h: innerRadiusPx * 2)
464
- let ring = NSBezierPath()
465
- ring.appendOval(in: outerRect)
466
- ring.appendOval(in: innerRect)
467
- ring.windingRule = .evenOdd
468
- ring.fill()
469
- case .groq:
470
- let slashWidthPx = 2
471
- let slashHeightPx = 8
472
- let path = NSBezierPath()
473
- path.move(to: point(x: centerXPx - slashWidthPx, y: centerYPx - slashHeightPx / 2))
474
- path.line(to: point(x: centerXPx, y: centerYPx - slashHeightPx / 2))
475
- path.line(to: point(x: centerXPx + slashWidthPx, y: centerYPx + slashHeightPx / 2))
476
- path.line(to: point(x: centerXPx, y: centerYPx + slashHeightPx / 2))
477
- path.close()
478
- path.fill()
479
- case .deepseek:
480
- let radiusPx = 4
481
- let dotPx = 2
482
- let outerRect = Self.grid.rect(
483
- x: centerXPx - radiusPx,
484
- y: centerYPx - radiusPx,
485
- w: radiusPx * 2,
486
- h: radiusPx * 2)
487
- NSBezierPath(ovalIn: outerRect).fill()
488
- let innerRect = Self.grid.rect(
489
- x: centerXPx - dotPx / 2,
490
- y: centerYPx - dotPx / 2,
491
- w: dotPx,
492
- h: dotPx)
493
- NSBezierPath(ovalIn: innerRect).fill()
494
- case .fireworks:
495
- let armPx = 5
496
- let armWidthPx = 2
497
- let vertical = Self.grid.rect(
498
- x: centerXPx - armWidthPx / 2,
499
- y: centerYPx - armPx,
500
- w: armWidthPx,
501
- h: armPx * 2)
502
- let horizontal = Self.grid.rect(
503
- x: centerXPx - armPx,
504
- y: centerYPx - armWidthPx / 2,
505
- w: armPx * 2,
506
- h: armWidthPx)
507
- NSBezierPath(rect: vertical).fill()
508
- NSBezierPath(rect: horizontal).fill()
509
- let diag = NSBezierPath()
510
- diag.move(to: point(x: centerXPx - 3, y: centerYPx - 3))
511
- diag.line(to: point(x: centerXPx - 1, y: centerYPx - 3))
512
- diag.line(to: point(x: centerXPx + 3, y: centerYPx + 1))
513
- diag.line(to: point(x: centerXPx + 3, y: centerYPx + 3))
514
- diag.line(to: point(x: centerXPx + 1, y: centerYPx + 3))
515
- diag.line(to: point(x: centerXPx - 3, y: centerYPx - 1))
516
- diag.close()
517
- diag.fill()
518
- case .mistral:
519
- let barWidthPx = 2
520
- let barGapPx = 1
521
- let barHeightPx = 6
522
- let totalWidth = barWidthPx * 3 + barGapPx * 2
523
- let startX = centerXPx - totalWidth / 2
524
- for idx in 0..<3 {
525
- let x = startX + idx * (barWidthPx + barGapPx)
526
- let rect = Self.grid.rect(
527
- x: x,
528
- y: centerYPx - barHeightPx / 2 + (idx == 1 ? 1 : 0),
529
- w: barWidthPx,
530
- h: barHeightPx - (idx == 1 ? 2 : 0))
531
- NSBezierPath(rect: rect).fill()
532
- }
533
- case .perplexity:
534
- let loopRadiusPx = 4
535
- let stemWidthPx = 2
536
- let stemHeightPx = 5
537
- let loopRect = Self.grid.rect(
538
- x: centerXPx - loopRadiusPx,
539
- y: centerYPx - loopRadiusPx,
540
- w: loopRadiusPx * 2,
541
- h: loopRadiusPx * 2)
542
- let innerRect = Self.grid.rect(
543
- x: centerXPx - 1,
544
- y: centerYPx - 1,
545
- w: 2,
546
- h: 2)
547
- let loop = NSBezierPath()
548
- loop.appendOval(in: loopRect)
549
- loop.appendOval(in: innerRect)
550
- loop.windingRule = .evenOdd
551
- loop.fill()
552
- let stemRect = Self.grid.rect(
553
- x: centerXPx + 1,
554
- y: centerYPx - loopRadiusPx - stemHeightPx + 1,
555
- w: stemWidthPx,
556
- h: stemHeightPx)
557
- NSBezierPath(rect: stemRect).fill()
558
- case .kimi:
559
- let ringRect = Self.grid.rect(
560
- x: centerXPx - 4,
561
- y: centerYPx - 4,
562
- w: 8,
563
- h: 8)
564
- let coreRect = Self.grid.rect(
565
- x: centerXPx - 1,
566
- y: centerYPx - 1,
567
- w: 2,
568
- h: 2)
569
- let ring = NSBezierPath()
570
- ring.appendOval(in: ringRect)
571
- ring.appendOval(in: coreRect)
572
- ring.windingRule = .evenOdd
573
- ring.fill()
574
- case .auggie:
575
- let armPx = 5
576
- let left = NSBezierPath()
577
- left.move(to: point(x: centerXPx - armPx, y: centerYPx - 3))
578
- left.line(to: point(x: centerXPx - 1, y: centerYPx + 4))
579
- left.line(to: point(x: centerXPx + 1, y: centerYPx + 4))
580
- left.line(to: point(x: centerXPx - 3, y: centerYPx - 3))
581
- left.close()
582
- left.fill()
583
- let right = NSBezierPath()
584
- right.move(to: point(x: centerXPx + armPx, y: centerYPx - 3))
585
- right.line(to: point(x: centerXPx + 1, y: centerYPx + 4))
586
- right.line(to: point(x: centerXPx - 1, y: centerYPx + 4))
587
- right.line(to: point(x: centerXPx + 3, y: centerYPx - 3))
588
- right.close()
589
- right.fill()
590
- case .together:
591
- let topRect = Self.grid.rect(
592
- x: centerXPx - 4,
593
- y: centerYPx + 1,
594
- w: 8,
595
- h: 2)
596
- let bottomRect = Self.grid.rect(
597
- x: centerXPx - 4,
598
- y: centerYPx - 3,
599
- w: 8,
600
- h: 2)
601
- let joinRect = Self.grid.rect(
602
- x: centerXPx - 1,
603
- y: centerYPx - 3,
604
- w: 2,
605
- h: 6)
606
- NSBezierPath(rect: topRect).fill()
607
- NSBezierPath(rect: bottomRect).fill()
608
- NSBezierPath(rect: joinRect).fill()
609
- case .cohere:
610
- let outerRect = Self.grid.rect(
611
- x: centerXPx - 4,
612
- y: centerYPx - 4,
613
- w: 8,
614
- h: 8)
615
- let innerRect = Self.grid.rect(
616
- x: centerXPx - 2,
617
- y: centerYPx - 2,
618
- w: 4,
619
- h: 4)
620
- let cPath = NSBezierPath()
621
- cPath.appendOval(in: outerRect)
622
- cPath.appendOval(in: innerRect)
623
- cPath.windingRule = .evenOdd
624
- cPath.fill()
625
- let cutRect = Self.grid.rect(
626
- x: centerXPx + 1,
627
- y: centerYPx - 4,
628
- w: 4,
629
- h: 8)
630
- NSBezierPath(rect: cutRect).fill()
631
- case .xai:
632
- let left = NSBezierPath()
633
- left.move(to: point(x: centerXPx - 4, y: centerYPx - 4))
634
- left.line(to: point(x: centerXPx - 1, y: centerYPx - 1))
635
- left.line(to: point(x: centerXPx - 4, y: centerYPx + 4))
636
- left.line(to: point(x: centerXPx - 2, y: centerYPx + 4))
637
- left.line(to: point(x: centerXPx + 1, y: centerYPx + 1))
638
- left.line(to: point(x: centerXPx + 4, y: centerYPx + 4))
639
- left.line(to: point(x: centerXPx + 4, y: centerYPx + 2))
640
- left.line(to: point(x: centerXPx + 1, y: centerYPx - 1))
641
- left.line(to: point(x: centerXPx + 4, y: centerYPx - 4))
642
- left.line(to: point(x: centerXPx + 2, y: centerYPx - 4))
643
- left.line(to: point(x: centerXPx - 1, y: centerYPx - 1))
644
- left.line(to: point(x: centerXPx - 4, y: centerYPx - 4))
645
- left.close()
646
- left.fill()
647
- case .cerebras:
648
- let outerRect = Self.grid.rect(
649
- x: centerXPx - 4,
650
- y: centerYPx - 4,
651
- w: 8,
652
- h: 8)
653
- let innerRect = Self.grid.rect(
654
- x: centerXPx - 2,
655
- y: centerYPx - 2,
656
- w: 4,
657
- h: 4)
658
- let ring = NSBezierPath()
659
- ring.appendOval(in: outerRect)
660
- ring.appendOval(in: innerRect)
661
- ring.windingRule = .evenOdd
662
- ring.fill()
663
- let notchRect = Self.grid.rect(
664
- x: centerXPx + 1,
665
- y: centerYPx - 2,
666
- w: 4,
667
- h: 4)
668
- NSBezierPath(rect: notchRect).fill()
669
- case .sambanova:
670
- let topArc = NSBezierPath()
671
- topArc.move(to: point(x: centerXPx - 4, y: centerYPx + 3))
672
- topArc.curve(
673
- to: point(x: centerXPx + 4, y: centerYPx + 3),
674
- controlPoint1: point(x: centerXPx - 1, y: centerYPx + 6),
675
- controlPoint2: point(x: centerXPx + 1, y: centerYPx + 6))
676
- topArc.line(to: point(x: centerXPx + 4, y: centerYPx + 1))
677
- topArc.curve(
678
- to: point(x: centerXPx - 4, y: centerYPx + 1),
679
- controlPoint1: point(x: centerXPx + 1, y: centerYPx + 4),
680
- controlPoint2: point(x: centerXPx - 1, y: centerYPx + 4))
681
- topArc.close()
682
- topArc.fill()
683
- let bottomArc = NSBezierPath()
684
- bottomArc.move(to: point(x: centerXPx + 4, y: centerYPx - 3))
685
- bottomArc.curve(
686
- to: point(x: centerXPx - 4, y: centerYPx - 3),
687
- controlPoint1: point(x: centerXPx + 1, y: centerYPx - 6),
688
- controlPoint2: point(x: centerXPx - 1, y: centerYPx - 6))
689
- bottomArc.line(to: point(x: centerXPx - 4, y: centerYPx - 1))
690
- bottomArc.curve(
691
- to: point(x: centerXPx + 4, y: centerYPx - 1),
692
- controlPoint1: point(x: centerXPx - 1, y: centerYPx - 4),
693
- controlPoint2: point(x: centerXPx + 1, y: centerYPx - 4))
694
- bottomArc.close()
695
- bottomArc.fill()
696
- case .azure:
697
- let outerRect = Self.grid.rect(
698
- x: centerXPx - 4,
699
- y: centerYPx - 4,
700
- w: 8,
701
- h: 8)
702
- let innerRect = Self.grid.rect(
703
- x: centerXPx - 2,
704
- y: centerYPx - 2,
705
- w: 4,
706
- h: 4)
707
- let ring = NSBezierPath()
708
- ring.appendOval(in: outerRect)
709
- ring.appendOval(in: innerRect)
710
- ring.windingRule = .evenOdd
711
- ring.fill()
712
- let slash = NSBezierPath()
713
- slash.move(to: point(x: centerXPx - 5, y: centerYPx - 1))
714
- slash.line(to: point(x: centerXPx - 3, y: centerYPx - 3))
715
- slash.line(to: point(x: centerXPx + 5, y: centerYPx + 5))
716
- slash.line(to: point(x: centerXPx + 3, y: centerYPx + 7))
717
- slash.close()
718
- slash.fill()
719
- case .bedrock:
720
- let top = NSBezierPath()
721
- top.move(to: point(x: centerXPx - 4, y: centerYPx + 2))
722
- top.line(to: point(x: centerXPx, y: centerYPx + 6))
723
- top.line(to: point(x: centerXPx + 4, y: centerYPx + 2))
724
- top.line(to: point(x: centerXPx + 2, y: centerYPx))
725
- top.line(to: point(x: centerXPx, y: centerYPx + 2))
726
- top.line(to: point(x: centerXPx - 2, y: centerYPx))
727
- top.close()
728
- top.fill()
729
- let bottom = NSBezierPath()
730
- bottom.move(to: point(x: centerXPx - 4, y: centerYPx - 2))
731
- bottom.line(to: point(x: centerXPx, y: centerYPx - 6))
732
- bottom.line(to: point(x: centerXPx + 4, y: centerYPx - 2))
733
- bottom.line(to: point(x: centerXPx + 2, y: centerYPx))
734
- bottom.line(to: point(x: centerXPx, y: centerYPx - 2))
735
- bottom.line(to: point(x: centerXPx - 2, y: centerYPx))
736
- bottom.close()
737
- bottom.fill()
738
- case .vertexai:
739
- let diamond = NSBezierPath()
740
- diamond.move(to: point(x: centerXPx, y: centerYPx + 6))
741
- diamond.line(to: point(x: centerXPx + 5, y: centerYPx))
742
- diamond.line(to: point(x: centerXPx, y: centerYPx - 6))
743
- diamond.line(to: point(x: centerXPx - 5, y: centerYPx))
744
- diamond.close()
745
- diamond.fill()
746
- case .zai:
747
- let slashGapPx = 3
748
- let slashWidthPx = 2
749
- let slashHeightPx = 7
750
- let leftPath = NSBezierPath()
751
- leftPath.move(to: point(x: centerXPx - slashGapPx, y: centerYPx - slashHeightPx / 2))
752
- leftPath.line(to: point(x: centerXPx - slashGapPx + slashWidthPx, y: centerYPx - slashHeightPx / 2))
753
- leftPath.line(to: point(x: centerXPx - slashGapPx + slashWidthPx + 2, y: centerYPx + slashHeightPx / 2))
754
- leftPath.line(to: point(x: centerXPx - slashGapPx + 2, y: centerYPx + slashHeightPx / 2))
755
- leftPath.close()
756
- let rightPath = NSBezierPath()
757
- rightPath.move(to: point(x: centerXPx + slashGapPx, y: centerYPx - slashHeightPx / 2))
758
- rightPath.line(to: point(x: centerXPx + slashGapPx + slashWidthPx, y: centerYPx - slashHeightPx / 2))
759
- rightPath.line(to: point(x: centerXPx + slashGapPx + slashWidthPx + 2, y: centerYPx + slashHeightPx / 2))
760
- rightPath.line(to: point(x: centerXPx + slashGapPx + 2, y: centerYPx + slashHeightPx / 2))
761
- rightPath.close()
762
- leftPath.fill()
763
- rightPath.fill()
764
- case .qwen:
765
- // Stylised "Q" ring -- outer circle punch with inner cutout.
766
- let ringOuter = 5
767
- let ringInner = 3
768
- let outerRect = Self.grid.rect(
769
- x: centerXPx - ringOuter,
770
- y: centerYPx - ringOuter,
771
- w: ringOuter * 2,
772
- h: ringOuter * 2)
773
- let innerRect = Self.grid.rect(
774
- x: centerXPx - ringInner,
775
- y: centerYPx - ringInner,
776
- w: ringInner * 2,
777
- h: ringInner * 2)
778
- NSBezierPath(ovalIn: outerRect).fill()
779
- ctx.setBlendMode(.normal)
780
- NSGraphicsContext.current?.cgContext.setFillColor(NSColor.clear.cgColor)
781
- ctx.setBlendMode(.clear)
782
- NSBezierPath(ovalIn: innerRect).fill()
783
- case .combined:
784
- let diamondRadiusPx = 4
785
- let cx = Self.grid.pt(centerXPx)
786
- let cy = Self.grid.pt(centerYPx)
787
- let r = Self.grid.pt(diamondRadiusPx)
788
- let path = NSBezierPath()
789
- path.move(to: NSPoint(x: cx, y: cy + r))
790
- path.line(to: NSPoint(x: cx + r, y: cy))
791
- path.line(to: NSPoint(x: cx, y: cy - r))
792
- path.line(to: NSPoint(x: cx - r, y: cy))
793
- path.close()
794
- path.fill()
795
- }
796
-
797
- ctx.restoreGState()
798
- }
799
-
800
- /// Morph helper: unbraids a simplified knot into our bar icon.
801
- static func makeMorphIcon(
802
- progress: Double,
803
- style: IconStyle,
804
- appearance: IconAppearance = .template) -> NSImage
805
- {
806
- let clamped = max(0, min(progress, 1))
807
- let key = self.morphCacheKey(progress: clamped, style: style, appearance: appearance)
808
- if let cached = self.morphCache.image(for: key) {
809
- return cached
810
- }
811
- let baseColor = appearance == .template
812
- ? NSColor.labelColor
813
- : self.vibrantAccentColor(pressure: 0.15, stale: false)
814
- let image = self.renderImage(isTemplate: appearance == .template) {
815
- self.drawUnbraidMorph(t: clamped, style: style, color: baseColor, appearance: appearance)
816
- }
817
- self.morphCache.set(image, for: key)
818
- return image
819
- }
820
-
821
- private static func iconFillPercent(
822
- primary: Double?,
823
- weekly: Double?,
824
- credits: Double?,
825
- dataMode: IconDataMode) -> Double
826
- {
827
- let value = primary ?? weekly ?? credits
828
- guard let value else { return 0 }
829
- let clamped = max(0, min(value / 100, 1))
830
- switch dataMode {
831
- case .remaining:
832
- return clamped
833
- case .used:
834
- return clamped
835
- }
836
- }
837
-
838
- private static func drawWaveLogo(
839
- fillPercent: Double,
840
- baseColor: NSColor,
841
- fillColor: NSColor)
842
- {
843
- guard let waveLogo = self.waveLogoTemplate,
844
- let ctx = NSGraphicsContext.current?.cgContext
845
- else {
846
- return
847
- }
848
-
849
- let rect = CGRect(origin: .zero, size: self.outputSize)
850
- let clamped = max(0, min(fillPercent, 1))
851
-
852
- // Base silhouette
853
- ctx.saveGState()
854
- waveLogo.draw(in: rect, from: .zero, operation: .sourceOver, fraction: 1.0)
855
- ctx.setBlendMode(.sourceIn)
856
- baseColor.setFill()
857
- ctx.fill(rect)
858
- ctx.restoreGState()
859
-
860
- // Usage fill: left-to-right reveal within the infinity symbol.
861
- guard clamped > 0 else { return }
862
- ctx.saveGState()
863
- waveLogo.draw(in: rect, from: .zero, operation: .sourceOver, fraction: 1.0)
864
- ctx.setBlendMode(.sourceIn)
865
- fillColor.setFill()
866
- let fillRect = CGRect(x: rect.minX, y: rect.minY, width: rect.width * clamped, height: rect.height)
867
- ctx.fill(fillRect)
868
- ctx.restoreGState()
869
- }
870
-
871
- private static func usagePressure(
872
- primary: Double?,
873
- weekly: Double?,
874
- credits: Double?,
875
- dataMode: IconDataMode) -> Double
876
- {
877
- let values = [primary, weekly, credits].compactMap(\.self)
878
- guard !values.isEmpty else { return 0 }
879
- let normalized = values.map { max(0, min($0 / 100, 1)) }
880
- switch dataMode {
881
- case .used:
882
- return normalized.max() ?? 0
883
- case .remaining:
884
- let minRemaining = normalized.min() ?? 1
885
- return max(0, min(1, 1 - minRemaining))
886
- }
887
- }
888
-
889
- private static func vibrantAccentColor(pressure: Double, stale: Bool) -> NSColor {
890
- let clamped = CGFloat(max(0, min(pressure, 1)))
891
- let safe = NSColor(calibratedRed: 0.12, green: 0.86, blue: 0.78, alpha: 1)
892
- let warn = NSColor(calibratedRed: 1.00, green: 0.72, blue: 0.30, alpha: 1)
893
- let hot = NSColor(calibratedRed: 1.00, green: 0.31, blue: 0.44, alpha: 1)
894
- let color: NSColor = if clamped <= 0.5 {
895
- self.mixColor(safe, warn, p: clamped / 0.5)
896
- } else {
897
- self.mixColor(warn, hot, p: (clamped - 0.5) / 0.5)
898
- }
899
- if stale {
900
- return color.withAlphaComponent(0.72)
901
- }
902
- return color
903
- }
904
-
905
- private static func mixColor(_ a: NSColor, _ b: NSColor, p: CGFloat) -> NSColor {
906
- guard let ca = a.usingColorSpace(.deviceRGB),
907
- let cb = b.usingColorSpace(.deviceRGB)
908
- else {
909
- return a
910
- }
911
- let clamped = max(0, min(p, 1))
912
- let red = ca.redComponent + (cb.redComponent - ca.redComponent) * clamped
913
- let green = ca.greenComponent + (cb.greenComponent - ca.greenComponent) * clamped
914
- let blue = ca.blueComponent + (cb.blueComponent - ca.blueComponent) * clamped
915
- let alpha = ca.alphaComponent + (cb.alphaComponent - ca.alphaComponent) * clamped
916
- return NSColor(calibratedRed: red, green: green, blue: blue, alpha: alpha)
917
- }
918
-
919
- private static func quantizedPercent(_ value: Double?) -> Int {
920
- guard let value else { return -1 }
921
- return Int((value * 10).rounded())
922
- }
923
-
924
- private static func quantizedCredits(_ value: Double?) -> Int {
925
- guard let value else { return -1 }
926
- let clamped = max(0, min(value, self.creditsCap))
927
- return Int((clamped * 10).rounded())
928
- }
929
-
930
- private static func styleKey(_ style: IconStyle) -> Int {
931
- switch style {
932
- case .codex: 0
933
- case .claude: 1
934
- case .zai: 2
935
- case .gemini: 3
936
- case .antigravity: 4
937
- case .cursor: 5
938
- case .factory: 6
939
- case .copilot: 7
940
- case .minimax: 8
941
- case .openrouter: 9
942
- case .groq: 10
943
- case .deepseek: 11
944
- case .fireworks: 12
945
- case .mistral: 13
946
- case .perplexity: 14
947
- case .kimi: 15
948
- case .auggie: 16
949
- case .together: 17
950
- case .cohere: 18
951
- case .xai: 19
952
- case .cerebras: 20
953
- case .sambanova: 21
954
- case .azure: 22
955
- case .bedrock: 23
956
- case .vertexai: 24
957
- case .qwen: 25
958
- case .combined: 99
959
- }
960
- }
961
-
962
- private static func indicatorKey(_ indicator: ProviderStatusIndicator) -> Int {
963
- switch indicator {
964
- case .none: 0
965
- case .minor: 1
966
- case .major: 2
967
- case .critical: 3
968
- case .maintenance: 4
969
- case .unknown: 5
970
- }
971
- }
972
-
973
- private static func appearanceKey(_ appearance: IconAppearance) -> Int {
974
- switch appearance {
975
- case .template: 0
976
- case .vibrant: 1
977
- }
978
- }
979
-
980
- private static func dataModeKey(_ mode: IconDataMode) -> Int {
981
- switch mode {
982
- case .remaining: 0
983
- case .used: 1
984
- }
985
- }
986
-
987
- private static func morphCacheKey(
988
- progress: Double,
989
- style: IconStyle,
990
- appearance: IconAppearance) -> NSNumber
991
- {
992
- let bucket = Int((progress * Double(self.morphBucketCount)).rounded())
993
- let key = self.styleKey(style) * 10000 + self.appearanceKey(appearance) * 1000 + bucket
994
- return NSNumber(value: key)
995
- }
996
-
997
- private static func cachedIcon(for key: IconCacheKey) -> NSImage? {
998
- self.iconCacheStore.cachedIcon(for: key)
999
- }
1000
-
1001
- private static func storeIcon(_ image: NSImage, for key: IconCacheKey) {
1002
- self.iconCacheStore.storeIcon(image, for: key, limit: self.iconCacheLimit)
1003
- }
1004
-
1005
- private static func drawUnbraidMorph(
1006
- t: Double,
1007
- style: IconStyle,
1008
- color: NSColor,
1009
- appearance: IconAppearance)
1010
- {
1011
- let t = CGFloat(max(0, min(t, 1)))
1012
- let size = Self.baseSize
1013
- let center = CGPoint(x: size.width / 2, y: size.height / 2)
1014
- let baseColor = color
1015
-
1016
- struct Segment {
1017
- let startCenter: CGPoint
1018
- let endCenter: CGPoint
1019
- let startAngle: CGFloat
1020
- let endAngle: CGFloat
1021
- let startLength: CGFloat
1022
- let endLength: CGFloat
1023
- let startThickness: CGFloat
1024
- let endThickness: CGFloat
1025
- let fadeOut: Bool
1026
- }
1027
-
1028
- let segments: [Segment] = [
1029
- // Upper ribbon -> top bar
1030
- .init(
1031
- startCenter: center.offset(dx: 0, dy: 2),
1032
- endCenter: CGPoint(x: center.x, y: 9.0),
1033
- startAngle: -30,
1034
- endAngle: 0,
1035
- startLength: 16,
1036
- endLength: 14,
1037
- startThickness: 3.4,
1038
- endThickness: 3.0,
1039
- fadeOut: false),
1040
- // Lower ribbon -> bottom bar
1041
- .init(
1042
- startCenter: center.offset(dx: 0, dy: -2),
1043
- endCenter: CGPoint(x: center.x, y: 4.0),
1044
- startAngle: 210,
1045
- endAngle: 0,
1046
- startLength: 16,
1047
- endLength: 12,
1048
- startThickness: 3.4,
1049
- endThickness: 2.4,
1050
- fadeOut: false),
1051
- // Side ribbon fades away
1052
- .init(
1053
- startCenter: center,
1054
- endCenter: center.offset(dx: 0, dy: 6),
1055
- startAngle: 90,
1056
- endAngle: 0,
1057
- startLength: 16,
1058
- endLength: 8,
1059
- startThickness: 3.4,
1060
- endThickness: 1.8,
1061
- fadeOut: true),
1062
- ]
1063
-
1064
- for seg in segments {
1065
- let p = seg.fadeOut ? t * 1.1 : t
1066
- let c = seg.startCenter.lerp(to: seg.endCenter, p: p)
1067
- let angle = seg.startAngle.lerp(to: seg.endAngle, p: p)
1068
- let length = seg.startLength.lerp(to: seg.endLength, p: p)
1069
- let thickness = seg.startThickness.lerp(to: seg.endThickness, p: p)
1070
- let alpha = seg.fadeOut ? (1 - p) : 1
1071
-
1072
- self.drawRoundedRibbon(
1073
- center: c,
1074
- length: length,
1075
- thickness: thickness,
1076
- angle: angle,
1077
- color: baseColor.withAlphaComponent(alpha))
1078
- }
1079
-
1080
- // Cross-fade in bar fill emphasis near the end of the morph.
1081
- if t > 0.55 {
1082
- let barT = (t - 0.55) / 0.45
1083
- let bars = self.makeIcon(
1084
- primaryRemaining: 100,
1085
- weeklyRemaining: 100,
1086
- creditsRemaining: nil,
1087
- stale: false,
1088
- style: style,
1089
- appearance: appearance)
1090
- bars.draw(in: CGRect(origin: .zero, size: size), from: .zero, operation: .sourceOver, fraction: barT)
1091
- }
1092
- }
1093
-
1094
- private static func drawRoundedRibbon(
1095
- center: CGPoint,
1096
- length: CGFloat,
1097
- thickness: CGFloat,
1098
- angle: CGFloat,
1099
- color: NSColor)
1100
- {
1101
- var transform = AffineTransform.identity
1102
- transform.translate(x: center.x, y: center.y)
1103
- transform.rotate(byDegrees: angle)
1104
- transform.translate(x: -center.x, y: -center.y)
1105
-
1106
- let rect = CGRect(
1107
- x: center.x - length / 2,
1108
- y: center.y - thickness / 2,
1109
- width: length,
1110
- height: thickness)
1111
-
1112
- let path = NSBezierPath(roundedRect: rect, xRadius: thickness / 2, yRadius: thickness / 2)
1113
- path.transform(using: transform)
1114
- color.setFill()
1115
- path.fill()
1116
- }
1117
-
1118
- private static func drawStatusOverlay(indicator: ProviderStatusIndicator, color: NSColor) {
1119
- guard indicator.hasIssue else { return }
1120
- switch indicator {
1121
- case .minor, .maintenance:
1122
- let size: CGFloat = 4
1123
- let rect = Self.snapRect(
1124
- x: Self.baseSize.width - size - 2,
1125
- y: 2,
1126
- width: size,
1127
- height: size)
1128
- let path = NSBezierPath(ovalIn: rect)
1129
- color.setFill()
1130
- path.fill()
1131
- case .major, .critical, .unknown:
1132
- let lineRect = Self.snapRect(
1133
- x: Self.baseSize.width - 6,
1134
- y: 4,
1135
- width: 2.0,
1136
- height: 6)
1137
- let linePath = NSBezierPath(roundedRect: lineRect, xRadius: 1, yRadius: 1)
1138
- color.setFill()
1139
- linePath.fill()
1140
-
1141
- let dotRect = Self.snapRect(
1142
- x: Self.baseSize.width - 6,
1143
- y: 2,
1144
- width: 2.0,
1145
- height: 2.0)
1146
- NSBezierPath(ovalIn: dotRect).fill()
1147
- case .none:
1148
- break
1149
- }
1150
- }
1151
-
1152
- private static func withScaledContext(_ draw: () -> Void) {
1153
- guard let ctx = NSGraphicsContext.current?.cgContext else {
1154
- draw()
1155
- return
1156
- }
1157
- ctx.saveGState()
1158
- ctx.setShouldAntialias(true)
1159
- ctx.interpolationQuality = .none
1160
- draw()
1161
- ctx.restoreGState()
1162
- }
1163
-
1164
- private static func snap(_ value: CGFloat) -> CGFloat {
1165
- (value * self.outputScale).rounded() / self.outputScale
1166
- }
1167
-
1168
- private static func snapRect(x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat) -> CGRect {
1169
- CGRect(x: self.snap(x), y: self.snap(y), width: self.snap(width), height: self.snap(height))
1170
- }
1171
-
1172
- private static func renderImage(isTemplate: Bool, _ draw: () -> Void) -> NSImage {
1173
- let image = NSImage(size: Self.outputSize)
1174
-
1175
- if let rep = NSBitmapImageRep(
1176
- bitmapDataPlanes: nil,
1177
- pixelsWide: Int(Self.outputSize.width * Self.outputScale),
1178
- pixelsHigh: Int(Self.outputSize.height * Self.outputScale),
1179
- bitsPerSample: 8,
1180
- samplesPerPixel: 4,
1181
- hasAlpha: true,
1182
- isPlanar: false,
1183
- colorSpaceName: .deviceRGB,
1184
- bytesPerRow: 0,
1185
- bitsPerPixel: 0)
1186
- {
1187
- rep.size = Self.outputSize // points
1188
- image.addRepresentation(rep)
1189
-
1190
- NSGraphicsContext.saveGraphicsState()
1191
- if let ctx = NSGraphicsContext(bitmapImageRep: rep) {
1192
- NSGraphicsContext.current = ctx
1193
- Self.withScaledContext(draw)
1194
- }
1195
- NSGraphicsContext.restoreGraphicsState()
1196
- } else {
1197
- // Fallback to legacy focus if the bitmap rep fails for any reason.
1198
- image.lockFocus()
1199
- Self.withScaledContext(draw)
1200
- image.unlockFocus()
1201
- }
1202
-
1203
- image.isTemplate = isTemplate
1204
- return image
1205
- }
1206
- }
1207
-
1208
- extension CGPoint {
1209
- fileprivate func lerp(to other: CGPoint, p: CGFloat) -> CGPoint {
1210
- CGPoint(x: self.x + (other.x - self.x) * p, y: self.y + (other.y - self.y) * p)
1211
- }
1212
-
1213
- fileprivate func offset(dx: CGFloat, dy: CGFloat) -> CGPoint {
1214
- CGPoint(x: self.x + dx, y: self.y + dy)
1215
- }
1216
- }
1217
-
1218
- extension CGFloat {
1219
- fileprivate func lerp(to other: CGFloat, p: CGFloat) -> CGFloat {
1220
- self + (other - self) * p
1221
- }
1222
- }