@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,135 @@
1
+ #if canImport(Darwin)
2
+ import Darwin
3
+ #else
4
+ import Glibc
5
+ #endif
6
+ import Foundation
7
+
8
+ public enum SubprocessRunnerError: LocalizedError, Sendable {
9
+ case binaryNotFound(String)
10
+ case launchFailed(String)
11
+ case timedOut(String)
12
+ case nonZeroExit(code: Int32, stderr: String)
13
+
14
+ public var errorDescription: String? {
15
+ switch self {
16
+ case let .binaryNotFound(binary):
17
+ return "Missing CLI '\(binary)'. Install it and restart Runic."
18
+ case let .launchFailed(details):
19
+ return "Failed to launch process: \(details)"
20
+ case let .timedOut(label):
21
+ return "Command timed out: \(label)"
22
+ case let .nonZeroExit(code, stderr):
23
+ let trimmed = stderr.trimmingCharacters(in: .whitespacesAndNewlines)
24
+ if trimmed.isEmpty {
25
+ return "Command failed with exit code \(code)."
26
+ }
27
+ return "Command failed (\(code)): \(trimmed)"
28
+ }
29
+ }
30
+ }
31
+
32
+ public struct SubprocessResult: Sendable {
33
+ public let stdout: String
34
+ public let stderr: String
35
+ }
36
+
37
+ public enum SubprocessRunner {
38
+ public static func run(
39
+ binary: String,
40
+ arguments: [String],
41
+ environment: [String: String],
42
+ timeout: TimeInterval,
43
+ label: String) async throws -> SubprocessResult
44
+ {
45
+ guard FileManager.default.isExecutableFile(atPath: binary) else {
46
+ throw SubprocessRunnerError.binaryNotFound(binary)
47
+ }
48
+
49
+ let process = Process()
50
+ process.executableURL = URL(fileURLWithPath: binary)
51
+ process.arguments = arguments
52
+ process.environment = environment
53
+
54
+ let stdoutPipe = Pipe()
55
+ let stderrPipe = Pipe()
56
+ process.standardOutput = stdoutPipe
57
+ process.standardError = stderrPipe
58
+ process.standardInput = nil
59
+
60
+ let stdoutTask = Task<Data, Never> {
61
+ stdoutPipe.fileHandleForReading.readDataToEndOfFile()
62
+ }
63
+ let stderrTask = Task<Data, Never> {
64
+ stderrPipe.fileHandleForReading.readDataToEndOfFile()
65
+ }
66
+
67
+ do {
68
+ try process.run()
69
+ } catch {
70
+ stdoutTask.cancel()
71
+ stderrTask.cancel()
72
+ stdoutPipe.fileHandleForReading.closeFile()
73
+ stderrPipe.fileHandleForReading.closeFile()
74
+ throw SubprocessRunnerError.launchFailed(error.localizedDescription)
75
+ }
76
+
77
+ var processGroup: pid_t?
78
+ let pid = process.processIdentifier
79
+ if setpgid(pid, pid) == 0 {
80
+ processGroup = pid
81
+ }
82
+
83
+ let exitCodeTask = Task<Int32, Never> {
84
+ process.waitUntilExit()
85
+ return process.terminationStatus
86
+ }
87
+
88
+ do {
89
+ let exitCode = try await withThrowingTaskGroup(of: Int32.self) { group in
90
+ group.addTask { await exitCodeTask.value }
91
+ group.addTask {
92
+ try await Task.sleep(for: .seconds(timeout))
93
+ throw SubprocessRunnerError.timedOut(label)
94
+ }
95
+ let code = try await group.next()!
96
+ group.cancelAll()
97
+ return code
98
+ }
99
+
100
+ let stdoutData = await stdoutTask.value
101
+ let stderrData = await stderrTask.value
102
+ let stdout = String(data: stdoutData, encoding: .utf8) ?? ""
103
+ let stderr = String(data: stderrData, encoding: .utf8) ?? ""
104
+
105
+ if exitCode != 0 {
106
+ throw SubprocessRunnerError.nonZeroExit(code: exitCode, stderr: stderr)
107
+ }
108
+
109
+ return SubprocessResult(stdout: stdout, stderr: stderr)
110
+ } catch {
111
+ if process.isRunning {
112
+ process.terminate()
113
+ if let pgid = processGroup {
114
+ kill(-pgid, SIGTERM)
115
+ }
116
+ let killDeadline = Date().addingTimeInterval(0.4)
117
+ while process.isRunning, Date() < killDeadline {
118
+ usleep(50000)
119
+ }
120
+ if process.isRunning {
121
+ if let pgid = processGroup {
122
+ kill(-pgid, SIGKILL)
123
+ }
124
+ kill(process.processIdentifier, SIGKILL)
125
+ }
126
+ }
127
+ exitCodeTask.cancel()
128
+ stdoutTask.cancel()
129
+ stderrTask.cancel()
130
+ stdoutPipe.fileHandleForReading.closeFile()
131
+ stderrPipe.fileHandleForReading.closeFile()
132
+ throw error
133
+ }
134
+ }
135
+ }
@@ -0,0 +1,173 @@
1
+ import Foundation
2
+
3
+ public struct GitCommit: Codable, Sendable, Hashable {
4
+ public let sha: String
5
+ public let shortSha: String
6
+ public let message: String
7
+ public let author: String
8
+ public let timestamp: Date
9
+
10
+ public init(sha: String, shortSha: String, message: String, author: String, timestamp: Date) {
11
+ self.sha = sha
12
+ self.shortSha = shortSha
13
+ self.message = message
14
+ self.author = author
15
+ self.timestamp = timestamp
16
+ }
17
+ }
18
+
19
+ public struct UsageWithCommit: Codable, Sendable, Hashable {
20
+ public let entry: UsageLedgerEntry
21
+ public let commit: GitCommit?
22
+
23
+ public init(entry: UsageLedgerEntry, commit: GitCommit?) {
24
+ self.entry = entry
25
+ self.commit = commit
26
+ }
27
+ }
28
+
29
+ public enum GitHubIntegration {
30
+ private static let logger = RunicLog.logger("github-integration")
31
+ private static let commitMatchWindow: TimeInterval = 300 // 5 minutes
32
+
33
+ public static func linkCommitsToUsage(
34
+ entries: [UsageLedgerEntry],
35
+ gitDirectory: URL? = nil) -> [UsageWithCommit]
36
+ {
37
+ guard !entries.isEmpty else { return [] }
38
+
39
+ let gitDir = gitDirectory ?? defaultGitDirectory()
40
+ let commits = loadCommits(from: gitDir)
41
+
42
+ guard !commits.isEmpty else {
43
+ self.logger.debug("No git commits found, returning entries without commit info")
44
+ return entries.map { UsageWithCommit(entry: $0, commit: nil) }
45
+ }
46
+
47
+ self.logger.debug("Linking \(entries.count) usage entries with \(commits.count) commits")
48
+
49
+ return entries.map { entry in
50
+ let matchedCommit = findClosestCommit(for: entry, in: commits)
51
+ return UsageWithCommit(entry: entry, commit: matchedCommit)
52
+ }
53
+ }
54
+
55
+ private static func defaultGitDirectory() -> URL {
56
+ let fileManager = FileManager.default
57
+ let currentDirectory = fileManager.currentDirectoryPath
58
+ return URL(fileURLWithPath: currentDirectory).appendingPathComponent(".git")
59
+ }
60
+
61
+ private static func loadCommits(from gitDirectory: URL) -> [GitCommit] {
62
+ let headLogPath = gitDirectory.appendingPathComponent("logs/HEAD")
63
+ let fileManager = FileManager.default
64
+
65
+ guard fileManager.fileExists(atPath: headLogPath.path) else {
66
+ self.logger.warning("Git HEAD log not found at \(headLogPath.path)")
67
+ return []
68
+ }
69
+
70
+ guard let contents = try? String(contentsOf: headLogPath, encoding: .utf8) else {
71
+ self.logger.error("Failed to read git HEAD log at \(headLogPath.path)")
72
+ return []
73
+ }
74
+
75
+ let lines = contents.components(separatedBy: .newlines).filter { !$0.isEmpty }
76
+ var commits: [GitCommit] = []
77
+
78
+ for line in lines {
79
+ if let commit = parseCommitLine(line) {
80
+ commits.append(commit)
81
+ }
82
+ }
83
+
84
+ self.logger.debug("Parsed \(commits.count) commits from git log")
85
+ return commits
86
+ }
87
+
88
+ private static func parseCommitLine(_ line: String) -> GitCommit? {
89
+ // Format: old_sha new_sha Author Name <email> timestamp timezone\tcommit: message
90
+ // Example: 0000000000000000000000000000000000000000 538b8f7ef4110664c161b13326a2ebe65b6a1fb0 Sriinnu <hello@srinivas.dev> 1767822510 +0100\tcommit (initial): Add Runic sources
91
+
92
+ let parts = line.components(separatedBy: "\t")
93
+ guard parts.count >= 2 else {
94
+ self.logger.trace("Skipping malformed git log line (no tab separator)")
95
+ return nil
96
+ }
97
+
98
+ let headerPart = parts[0]
99
+ let messagePart = parts[1]
100
+
101
+ // Parse header: old_sha new_sha author timestamp timezone
102
+ let headerComponents = headerPart.components(separatedBy: " ")
103
+ guard headerComponents.count >= 5 else {
104
+ self.logger.trace("Skipping malformed git log header")
105
+ return nil
106
+ }
107
+
108
+ let newSha = headerComponents[1]
109
+ guard newSha != "0000000000000000000000000000000000000000" else {
110
+ self.logger.trace("Skipping null SHA")
111
+ return nil
112
+ }
113
+
114
+ // Extract timestamp (Unix epoch)
115
+ let timestampIndex = headerComponents.count - 2
116
+ guard let timestampValue = Double(headerComponents[timestampIndex]) else {
117
+ self.logger.trace("Failed to parse timestamp from git log")
118
+ return nil
119
+ }
120
+
121
+ let timestamp = Date(timeIntervalSince1970: timestampValue)
122
+
123
+ // Extract author (everything between sha and timestamp)
124
+ let authorEndIndex = timestampIndex
125
+ let authorComponents = Array(headerComponents[2..<authorEndIndex])
126
+ let author = authorComponents.joined(separator: " ")
127
+
128
+ // Extract message (remove "commit: " or "commit (initial): " prefix if present)
129
+ var message = messagePart
130
+ if message.hasPrefix("commit: ") {
131
+ message = String(message.dropFirst(8))
132
+ } else if message.hasPrefix("commit (initial): ") {
133
+ message = String(message.dropFirst(18))
134
+ } else if message.contains(": ") {
135
+ // Handle other prefixes like "pull", "merge", "rebase", etc.
136
+ if let colonIndex = message.firstIndex(of: ":") {
137
+ message = String(message[message.index(after: colonIndex)...]).trimmingCharacters(in: .whitespaces)
138
+ }
139
+ }
140
+
141
+ let shortSha = String(newSha.prefix(7))
142
+
143
+ return GitCommit(
144
+ sha: newSha,
145
+ shortSha: shortSha,
146
+ message: message,
147
+ author: author,
148
+ timestamp: timestamp)
149
+ }
150
+
151
+ private static func findClosestCommit(
152
+ for entry: UsageLedgerEntry,
153
+ in commits: [GitCommit]) -> GitCommit?
154
+ {
155
+ // Find commits within the 5-minute window
156
+ let entryTime = entry.timestamp
157
+ let matchingCommits = commits.filter { commit in
158
+ let timeDiff = abs(commit.timestamp.timeIntervalSince(entryTime))
159
+ return timeDiff <= self.commitMatchWindow
160
+ }
161
+
162
+ guard !matchingCommits.isEmpty else {
163
+ return nil
164
+ }
165
+
166
+ // Return the commit with the smallest time difference
167
+ return matchingCommits.min { commit1, commit2 in
168
+ let diff1 = abs(commit1.timestamp.timeIntervalSince(entryTime))
169
+ let diff2 = abs(commit2.timestamp.timeIntervalSince(entryTime))
170
+ return diff1 < diff2
171
+ }
172
+ }
173
+ }
@@ -0,0 +1,79 @@
1
+ import Foundation
2
+ import Logging
3
+ #if canImport(Darwin)
4
+ import Darwin
5
+ #else
6
+ import Glibc
7
+ #endif
8
+
9
+ struct JSONStderrLogHandler: LogHandler {
10
+ var metadata: Logger.Metadata = [:]
11
+ var logLevel: Logger.Level = .info
12
+
13
+ private let label: String
14
+ private let encoder: JSONEncoder
15
+
16
+ init(label: String) {
17
+ self.label = label
18
+ self.encoder = JSONEncoder()
19
+ self.encoder.dateEncodingStrategy = .iso8601
20
+ self.encoder.outputFormatting = [.sortedKeys]
21
+ }
22
+
23
+ subscript(metadataKey metadataKey: String) -> Logger.Metadata.Value? {
24
+ get { self.metadata[metadataKey] }
25
+ set { self.metadata[metadataKey] = newValue }
26
+ }
27
+
28
+ // swiftlint:disable:next function_parameter_count
29
+ func log(
30
+ level: Logger.Level,
31
+ message: Logger.Message,
32
+ metadata: Logger.Metadata?,
33
+ source: String,
34
+ file: String,
35
+ function: String,
36
+ line: UInt)
37
+ {
38
+ let ts = Date()
39
+ var combined = self.metadata
40
+ if let metadata { combined.merge(metadata, uniquingKeysWith: { _, new in new }) }
41
+
42
+ let payload = JSONLogLine(
43
+ timestamp: ts,
44
+ level: level.rawValue,
45
+ label: self.label,
46
+ message: message.description,
47
+ source: source,
48
+ file: file,
49
+ function: function,
50
+ line: line,
51
+ metadata: combined.isEmpty ? nil : combined.mapValues(\.description))
52
+
53
+ guard let data = try? self.encoder.encode(payload),
54
+ let text = String(data: data, encoding: .utf8) else { return }
55
+ Self.writeStderr(text + "\n")
56
+ }
57
+ }
58
+
59
+ private struct JSONLogLine: Encodable {
60
+ let timestamp: Date
61
+ let level: String
62
+ let label: String
63
+ let message: String
64
+ let source: String
65
+ let file: String
66
+ let function: String
67
+ let line: UInt
68
+ let metadata: [String: String]?
69
+ }
70
+
71
+ extension JSONStderrLogHandler {
72
+ private static func writeStderr(_ text: String) {
73
+ let bytes = Array(text.utf8)
74
+ bytes.withUnsafeBytes { buffer in
75
+ guard let baseAddress = buffer.baseAddress else { return }
76
+ _ = write(STDERR_FILENO, baseAddress, buffer.count)
77
+ }
78
+ }
79
+ }
@@ -0,0 +1,86 @@
1
+ #if canImport(os)
2
+ import Foundation
3
+ import Logging
4
+ import os
5
+
6
+ struct OSLogLogHandler: LogHandler {
7
+ var metadata: Logging.Logger.Metadata = [:]
8
+ var logLevel: Logging.Logger.Level = .info
9
+
10
+ private let label: String
11
+ private let subsystem: String
12
+ private let logger: os.Logger
13
+
14
+ init(label: String, subsystem: String) {
15
+ self.label = label
16
+ self.subsystem = subsystem
17
+ let category = Self.category(from: label, subsystem: subsystem)
18
+ self.logger = os.Logger(subsystem: subsystem, category: category)
19
+ }
20
+
21
+ subscript(metadataKey metadataKey: String) -> Logging.Logger.Metadata.Value? {
22
+ get { self.metadata[metadataKey] }
23
+ set { self.metadata[metadataKey] = newValue }
24
+ }
25
+
26
+ // swiftlint:disable:next function_parameter_count
27
+ func log(
28
+ level: Logging.Logger.Level,
29
+ message: Logging.Logger.Message,
30
+ metadata: Logging.Logger.Metadata?,
31
+ source: String,
32
+ file: String,
33
+ function: String,
34
+ line: UInt)
35
+ {
36
+ let msg = Self.decorate(
37
+ message: message.description,
38
+ label: self.label,
39
+ subsystem: self.subsystem,
40
+ metadata: self.metadata,
41
+ extraMetadata: metadata)
42
+
43
+ switch level {
44
+ case .trace:
45
+ self.logger.debug("\(msg, privacy: .public)")
46
+ case .debug:
47
+ self.logger.debug("\(msg, privacy: .public)")
48
+ case .info, .notice:
49
+ self.logger.info("\(msg, privacy: .public)")
50
+ case .warning:
51
+ self.logger.warning("\(msg, privacy: .public)")
52
+ case .error:
53
+ self.logger.error("\(msg, privacy: .public)")
54
+ case .critical:
55
+ self.logger.fault("\(msg, privacy: .public)")
56
+ }
57
+ }
58
+
59
+ private static func category(from label: String, subsystem: String) -> String {
60
+ let prefix = subsystem + "."
61
+ guard label.hasPrefix(prefix) else { return label }
62
+ return String(label.dropFirst(prefix.count))
63
+ }
64
+
65
+ private static func decorate(
66
+ message: String,
67
+ label: String,
68
+ subsystem: String,
69
+ metadata: Logging.Logger.Metadata,
70
+ extraMetadata: Logging.Logger.Metadata?)
71
+ -> String
72
+ {
73
+ var merged = metadata
74
+ if let extraMetadata { merged.merge(extraMetadata, uniquingKeysWith: { _, new in new }) }
75
+ guard !merged.isEmpty else { return message }
76
+
77
+ let suffix = merged
78
+ .sorted(by: { $0.key < $1.key })
79
+ .map { "\($0.key)=\($0.value)" }
80
+ .joined(separator: " ")
81
+ _ = label
82
+ _ = subsystem
83
+ return "\(message) (\(suffix))"
84
+ }
85
+ }
86
+ #endif
@@ -0,0 +1,123 @@
1
+ import Foundation
2
+ import Logging
3
+
4
+ public enum RunicLog {
5
+ public enum Destination: Sendable {
6
+ case stderr
7
+ case oslog(subsystem: String)
8
+ }
9
+
10
+ public enum Level: String, Sendable {
11
+ case trace
12
+ case verbose
13
+ case debug
14
+ case info
15
+ case warning
16
+ case error
17
+ case critical
18
+
19
+ public var asSwiftLogLevel: Logger.Level {
20
+ switch self {
21
+ case .trace: .trace
22
+ case .verbose: .debug
23
+ case .debug: .debug
24
+ case .info: .info
25
+ case .warning: .warning
26
+ case .error: .error
27
+ case .critical: .critical
28
+ }
29
+ }
30
+ }
31
+
32
+ public struct Configuration: Sendable {
33
+ public let destination: Destination
34
+ public let level: Level
35
+ public let json: Bool
36
+
37
+ public init(destination: Destination, level: Level, json: Bool) {
38
+ self.destination = destination
39
+ self.level = level
40
+ self.json = json
41
+ }
42
+ }
43
+
44
+ private static let lock = NSLock()
45
+ private nonisolated(unsafe) static var isBootstrapped = false
46
+
47
+ public static func bootstrapIfNeeded(_ config: Configuration) {
48
+ self.lock.lock()
49
+ defer { lock.unlock() }
50
+ guard !self.isBootstrapped else { return }
51
+
52
+ let baseFactory: @Sendable (String) -> any LogHandler = { label in
53
+ switch config.destination {
54
+ case .stderr:
55
+ if config.json { return JSONStderrLogHandler(label: label) }
56
+ return StreamLogHandler.standardError(label: label)
57
+ case let .oslog(subsystem):
58
+ #if canImport(os)
59
+ return OSLogLogHandler(label: label, subsystem: subsystem)
60
+ #else
61
+ if config.json { return JSONStderrLogHandler(label: label) }
62
+ return StreamLogHandler.standardError(label: label)
63
+ #endif
64
+ }
65
+ }
66
+
67
+ LoggingSystem.bootstrap { label in
68
+ var handler = baseFactory(label)
69
+ handler.logLevel = config.level.asSwiftLogLevel
70
+ return handler
71
+ }
72
+
73
+ self.isBootstrapped = true
74
+ }
75
+
76
+ public static func logger(_ category: String) -> RunicLogger {
77
+ let logger = Logger(label: "com.sriinnu.athena.runic.\(category)")
78
+ return RunicLogger { level, message, metadata in
79
+ let swiftLogLevel = level.asSwiftLogLevel
80
+ let meta = metadata?.reduce(into: Logger.Metadata()) { partial, entry in
81
+ partial[entry.key] = .string(entry.value)
82
+ }
83
+ logger.log(level: swiftLogLevel, "\(message)", metadata: meta)
84
+ }
85
+ }
86
+
87
+ public static func parseLevel(_ raw: String?) -> Level? {
88
+ guard let raw, !raw.isEmpty else { return nil }
89
+ return Level(rawValue: raw.trimmingCharacters(in: .whitespacesAndNewlines).lowercased())
90
+ }
91
+ }
92
+
93
+ public struct RunicLogger: Sendable {
94
+ private let logFn: @Sendable (RunicLog.Level, String, [String: String]?) -> Void
95
+
96
+ fileprivate init(_ logFn: @escaping @Sendable (RunicLog.Level, String, [String: String]?) -> Void) {
97
+ self.logFn = logFn
98
+ }
99
+
100
+ public func trace(_ message: @autoclosure () -> String, metadata: [String: String]? = nil) {
101
+ self.logFn(.trace, message(), metadata)
102
+ }
103
+
104
+ public func debug(_ message: @autoclosure () -> String, metadata: [String: String]? = nil) {
105
+ self.logFn(.debug, message(), metadata)
106
+ }
107
+
108
+ public func info(_ message: @autoclosure () -> String, metadata: [String: String]? = nil) {
109
+ self.logFn(.info, message(), metadata)
110
+ }
111
+
112
+ public func warning(_ message: @autoclosure () -> String, metadata: [String: String]? = nil) {
113
+ self.logFn(.warning, message(), metadata)
114
+ }
115
+
116
+ public func error(_ message: @autoclosure () -> String, metadata: [String: String]? = nil) {
117
+ self.logFn(.error, message(), metadata)
118
+ }
119
+
120
+ public func critical(_ message: @autoclosure () -> String, metadata: [String: String]? = nil) {
121
+ self.logFn(.critical, message(), metadata)
122
+ }
123
+ }