@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,287 +0,0 @@
1
- import CloudKit
2
- import Foundation
3
-
4
- // MARK: - Sync Protocol Definitions
5
-
6
- /// Protocol defining the core synchronization engine interface
7
- ///
8
- /// This protocol abstracts the synchronization logic to allow for different
9
- /// implementations (CloudKit, custom server, etc.) while maintaining a
10
- /// consistent API for syncing data across devices.
11
- public protocol SyncEngine: Sendable {
12
- /// Synchronizes local data with remote storage
13
- ///
14
- /// - Parameter options: Configuration options for this sync operation
15
- /// - Returns: Result indicating success or failure with error details
16
- func sync(options: SyncOptions) async -> Result<SyncResult, SyncError>
17
-
18
- /// Pushes local changes to remote storage
19
- ///
20
- /// - Parameter records: Array of records to push
21
- /// - Returns: Result containing pushed record identifiers or error
22
- func push(records: [SyncableRecord]) async -> Result<[String], SyncError>
23
-
24
- /// Fetches changes from remote storage
25
- ///
26
- /// - Parameter recordTypes: Array of record type names to fetch
27
- /// - Returns: Result containing fetched records or error
28
- func fetch(recordTypes: [String]) async -> Result<[SyncableRecord], SyncError>
29
-
30
- /// Deletes records from remote storage
31
- ///
32
- /// - Parameter recordIDs: Array of record identifiers to delete
33
- /// - Returns: Result containing deleted record identifiers or error
34
- func delete(recordIDs: [String]) async -> Result<[String], SyncError>
35
-
36
- /// Resets sync state and clears all remote data
37
- ///
38
- /// - Warning: This operation is destructive and cannot be undone
39
- /// - Returns: Result indicating success or failure
40
- func resetSync() async -> Result<Void, SyncError>
41
- }
42
-
43
- // MARK: - Syncable Record Protocol
44
-
45
- /// Protocol for objects that can be synchronized across devices
46
- ///
47
- /// Conform to this protocol to enable CloudKit synchronization for your data types.
48
- public protocol SyncableRecord: Sendable, Codable {
49
- /// Unique identifier for the record
50
- var recordID: String { get }
51
-
52
- /// Type name used for CloudKit record type
53
- var recordType: String { get }
54
-
55
- /// Version number for conflict resolution
56
- var version: Int { get }
57
-
58
- /// Last modification timestamp
59
- var modifiedAt: Date { get }
60
-
61
- /// Device identifier that last modified this record
62
- var lastModifiedDeviceID: String? { get }
63
-
64
- /// Converts the record to a CloudKit CKRecord
65
- ///
66
- /// - Returns: CloudKit record representation
67
- func toCKRecord() throws -> CKRecord
68
-
69
- /// Creates a record from a CloudKit CKRecord
70
- ///
71
- /// - Parameter ckRecord: CloudKit record to convert
72
- /// - Returns: Initialized syncable record
73
- static func fromCKRecord(_ ckRecord: CKRecord) throws -> Self
74
- }
75
-
76
- // MARK: - Sync Conflict Resolver Protocol
77
-
78
- /// Protocol for resolving conflicts when multiple devices modify the same record
79
- ///
80
- /// Implement this protocol to define custom conflict resolution strategies
81
- /// beyond the default last-write-wins behavior.
82
- public protocol SyncConflictResolverProtocol: Sendable {
83
- /// Resolves a conflict between local and remote versions of a record
84
- ///
85
- /// - Parameters:
86
- /// - local: The local version of the conflicting record
87
- /// - remote: The remote version of the conflicting record
88
- /// - strategy: The conflict resolution strategy to apply
89
- /// - Returns: The resolved record that should be kept
90
- func resolve(
91
- local: SyncableRecord,
92
- remote: SyncableRecord,
93
- strategy: ConflictResolutionStrategy) async -> SyncableRecord
94
- }
95
-
96
- // MARK: - Sync Observer Protocol
97
-
98
- /// Protocol for observing synchronization events
99
- ///
100
- /// Implement this protocol to receive notifications about sync state changes,
101
- /// progress updates, and completion events.
102
- public protocol SyncObserver: AnyObject, Sendable {
103
- /// Called when synchronization begins
104
- func syncDidStart()
105
-
106
- /// Called when synchronization progress updates
107
- ///
108
- /// - Parameters:
109
- /// - current: Number of records processed
110
- /// - total: Total number of records to process
111
- func syncDidProgress(current: Int, total: Int)
112
-
113
- /// Called when synchronization completes successfully
114
- ///
115
- /// - Parameter result: The sync result containing statistics
116
- func syncDidComplete(result: SyncResult)
117
-
118
- /// Called when synchronization fails
119
- ///
120
- /// - Parameter error: The error that caused the failure
121
- func syncDidFail(error: SyncError)
122
- }
123
-
124
- // MARK: - Supporting Types
125
-
126
- /// Configuration options for sync operations
127
- public struct SyncOptions: Sendable {
128
- /// Whether to force a full sync, ignoring change tracking
129
- public let forceFullSync: Bool
130
-
131
- /// Maximum number of records to sync in a single batch
132
- public let batchSize: Int
133
-
134
- /// Conflict resolution strategy to use
135
- public let conflictStrategy: ConflictResolutionStrategy
136
-
137
- /// Whether to sync in background mode
138
- public let backgroundMode: Bool
139
-
140
- /// Timeout interval for sync operations
141
- public let timeout: TimeInterval
142
-
143
- /// Whether to encrypt sensitive data
144
- public let encryptSensitiveData: Bool
145
-
146
- public init(
147
- forceFullSync: Bool = false,
148
- batchSize: Int = 100,
149
- conflictStrategy: ConflictResolutionStrategy = .lastWriteWins,
150
- backgroundMode: Bool = false,
151
- timeout: TimeInterval = 60.0,
152
- encryptSensitiveData: Bool = true)
153
- {
154
- self.forceFullSync = forceFullSync
155
- self.batchSize = batchSize
156
- self.conflictStrategy = conflictStrategy
157
- self.backgroundMode = backgroundMode
158
- self.timeout = timeout
159
- self.encryptSensitiveData = encryptSensitiveData
160
- }
161
- }
162
-
163
- /// Result of a sync operation with statistics
164
- public struct SyncResult: Sendable {
165
- /// Number of records successfully pushed
166
- public let pushedCount: Int
167
-
168
- /// Number of records successfully fetched
169
- public let fetchedCount: Int
170
-
171
- /// Number of conflicts resolved
172
- public let conflictsResolved: Int
173
-
174
- /// Number of records deleted
175
- public let deletedCount: Int
176
-
177
- /// Timestamp when sync completed
178
- public let completedAt: Date
179
-
180
- /// Duration of the sync operation
181
- public let duration: TimeInterval
182
-
183
- /// Any non-fatal warnings encountered
184
- public let warnings: [String]
185
-
186
- public init(
187
- pushedCount: Int = 0,
188
- fetchedCount: Int = 0,
189
- conflictsResolved: Int = 0,
190
- deletedCount: Int = 0,
191
- completedAt: Date = Date(),
192
- duration: TimeInterval = 0,
193
- warnings: [String] = [])
194
- {
195
- self.pushedCount = pushedCount
196
- self.fetchedCount = fetchedCount
197
- self.conflictsResolved = conflictsResolved
198
- self.deletedCount = deletedCount
199
- self.completedAt = completedAt
200
- self.duration = duration
201
- self.warnings = warnings
202
- }
203
- }
204
-
205
- /// Conflict resolution strategies
206
- public enum ConflictResolutionStrategy: String, Codable, Sendable {
207
- /// Keep the most recently modified record (default)
208
- case lastWriteWins
209
-
210
- /// Keep the local version
211
- case preferLocal
212
-
213
- /// Keep the remote version
214
- case preferRemote
215
-
216
- /// Keep the version with higher version number
217
- case highestVersion
218
-
219
- /// Merge both versions (requires custom merge logic)
220
- case merge
221
- }
222
-
223
- /// Errors that can occur during synchronization
224
- public enum SyncError: Error, Sendable {
225
- /// iCloud account is not available
226
- case iCloudAccountUnavailable
227
-
228
- /// Network connection is not available
229
- case networkUnavailable
230
-
231
- /// CloudKit quota exceeded
232
- case quotaExceeded
233
-
234
- /// Record format is invalid
235
- case invalidRecordFormat(String)
236
-
237
- /// Sync operation timed out
238
- case timeout
239
-
240
- /// Authentication failed
241
- case authenticationFailed
242
-
243
- /// Conflict could not be resolved
244
- case conflictResolutionFailed(String)
245
-
246
- /// Generic CloudKit error
247
- case cloudKitError(Error)
248
-
249
- /// Encryption/decryption failed
250
- case encryptionFailed(String)
251
-
252
- /// Unknown error occurred
253
- case unknown(Error)
254
-
255
- public var localizedDescription: String {
256
- switch self {
257
- case .iCloudAccountUnavailable:
258
- "iCloud account is not available. Please sign in to iCloud in Settings."
259
- case .networkUnavailable:
260
- "Network connection is not available. Sync will retry when online."
261
- case .quotaExceeded:
262
- "iCloud storage quota exceeded. Please free up space or upgrade your plan."
263
- case let .invalidRecordFormat(details):
264
- "Invalid record format: \(details)"
265
- case .timeout:
266
- "Sync operation timed out. Please try again."
267
- case .authenticationFailed:
268
- "Authentication failed. Please sign in again."
269
- case let .conflictResolutionFailed(details):
270
- "Failed to resolve conflict: \(details)"
271
- case let .cloudKitError(error):
272
- "CloudKit error: \(error.localizedDescription)"
273
- case let .encryptionFailed(details):
274
- "Encryption failed: \(details)"
275
- case let .unknown(error):
276
- "Unknown error: \(error.localizedDescription)"
277
- }
278
- }
279
- }
280
-
281
- /// Priority levels for sync operations
282
- public enum SyncPriority: Int, Sendable {
283
- case low = 0
284
- case normal = 1
285
- case high = 2
286
- case critical = 3
287
- }
@@ -1,402 +0,0 @@
1
- import CloudKit
2
- import CryptoKit
3
- import Foundation
4
- import LocalAuthentication
5
-
6
- // MARK: - CloudKit Record Type Constants
7
-
8
- /// CloudKit record type identifiers
9
- public enum CloudKitRecordType {
10
- public static let usageSnapshot = "UsageSnapshot"
11
- public static let userPreferences = "UserPreferences"
12
- public static let alertConfiguration = "AlertConfiguration"
13
- public static let syncMetadata = "SyncMetadata"
14
- }
15
-
16
- // MARK: - Usage Snapshot Sync Record
17
-
18
- /// Syncable usage snapshot record for cross-device synchronization
19
- ///
20
- /// This record encapsulates usage data that can be synchronized across
21
- /// devices using CloudKit, with support for encryption and versioning.
22
- public struct UsageSnapshotSyncRecord: SyncableRecord {
23
- public let recordID: String
24
- public let recordType: String = CloudKitRecordType.usageSnapshot
25
- public let version: Int
26
- public let modifiedAt: Date
27
- public let lastModifiedDeviceID: String?
28
-
29
- // Usage data
30
- public let providerID: String
31
- public let primaryUsed: Int
32
- public let primaryLimit: Int?
33
- public let secondaryUsed: Int?
34
- public let secondaryLimit: Int?
35
- public let costUSD: Double?
36
- public let accountEmail: String?
37
- public let updatedAt: Date
38
-
39
- // Metadata
40
- public let deviceName: String
41
- public let platform: String
42
-
43
- public init(
44
- recordID: String = UUID().uuidString,
45
- version: Int = 1,
46
- modifiedAt: Date = Date(),
47
- lastModifiedDeviceID: String? = nil,
48
- providerID: String,
49
- primaryUsed: Int,
50
- primaryLimit: Int?,
51
- secondaryUsed: Int? = nil,
52
- secondaryLimit: Int? = nil,
53
- costUSD: Double? = nil,
54
- accountEmail: String? = nil,
55
- updatedAt: Date = Date(),
56
- deviceName: String,
57
- platform: String)
58
- {
59
- self.recordID = recordID
60
- self.version = version
61
- self.modifiedAt = modifiedAt
62
- self.lastModifiedDeviceID = lastModifiedDeviceID
63
- self.providerID = providerID
64
- self.primaryUsed = primaryUsed
65
- self.primaryLimit = primaryLimit
66
- self.secondaryUsed = secondaryUsed
67
- self.secondaryLimit = secondaryLimit
68
- self.costUSD = costUSD
69
- self.accountEmail = accountEmail
70
- self.updatedAt = updatedAt
71
- self.deviceName = deviceName
72
- self.platform = platform
73
- }
74
-
75
- public func toCKRecord() throws -> CKRecord {
76
- let record = CKRecord(recordType: recordType, recordID: CKRecord.ID(recordName: self.recordID))
77
-
78
- record["version"] = self.version as CKRecordValue
79
- record["modifiedAt"] = self.modifiedAt as CKRecordValue
80
- record["lastModifiedDeviceID"] = self.lastModifiedDeviceID as? CKRecordValue
81
- record["providerID"] = self.providerID as CKRecordValue
82
- record["primaryUsed"] = self.primaryUsed as CKRecordValue
83
- record["primaryLimit"] = self.primaryLimit as? CKRecordValue
84
- record["secondaryUsed"] = self.secondaryUsed as? CKRecordValue
85
- record["secondaryLimit"] = self.secondaryLimit as? CKRecordValue
86
- record["costUSD"] = self.costUSD as? CKRecordValue
87
- record["updatedAt"] = self.updatedAt as CKRecordValue
88
- record["deviceName"] = self.deviceName as CKRecordValue
89
- record["platform"] = self.platform as CKRecordValue
90
-
91
- // Encrypt sensitive data
92
- if let email = accountEmail {
93
- let encrypted = try encryptString(email)
94
- record["accountEmail"] = encrypted as CKRecordValue
95
- }
96
-
97
- return record
98
- }
99
-
100
- public static func fromCKRecord(_ ckRecord: CKRecord) throws -> UsageSnapshotSyncRecord {
101
- guard let version = ckRecord["version"] as? Int,
102
- let modifiedAt = ckRecord["modifiedAt"] as? Date,
103
- let providerID = ckRecord["providerID"] as? String,
104
- let primaryUsed = ckRecord["primaryUsed"] as? Int,
105
- let updatedAt = ckRecord["updatedAt"] as? Date,
106
- let deviceName = ckRecord["deviceName"] as? String,
107
- let platform = ckRecord["platform"] as? String
108
- else {
109
- throw SyncError.invalidRecordFormat("Missing required fields in UsageSnapshot")
110
- }
111
-
112
- var accountEmail: String?
113
- if let encryptedEmail = ckRecord["accountEmail"] as? String {
114
- accountEmail = try? decryptString(encryptedEmail)
115
- }
116
-
117
- return UsageSnapshotSyncRecord(
118
- recordID: ckRecord.recordID.recordName,
119
- version: version,
120
- modifiedAt: modifiedAt,
121
- lastModifiedDeviceID: ckRecord["lastModifiedDeviceID"] as? String,
122
- providerID: providerID,
123
- primaryUsed: primaryUsed,
124
- primaryLimit: ckRecord["primaryLimit"] as? Int,
125
- secondaryUsed: ckRecord["secondaryUsed"] as? Int,
126
- secondaryLimit: ckRecord["secondaryLimit"] as? Int,
127
- costUSD: ckRecord["costUSD"] as? Double,
128
- accountEmail: accountEmail,
129
- updatedAt: updatedAt,
130
- deviceName: deviceName,
131
- platform: platform)
132
- }
133
- }
134
-
135
- // MARK: - User Preferences Sync Record
136
-
137
- /// Syncable user preferences record
138
- ///
139
- /// Stores user preferences and settings that should be synchronized
140
- /// across all devices where the user is signed in.
141
- public struct UserPreferencesSyncRecord: SyncableRecord {
142
- public let recordID: String
143
- public let recordType: String = CloudKitRecordType.userPreferences
144
- public let version: Int
145
- public let modifiedAt: Date
146
- public let lastModifiedDeviceID: String?
147
-
148
- // Preferences
149
- public let refreshInterval: TimeInterval
150
- public let enabledProviders: [String]
151
- public let notificationsEnabled: Bool
152
- public let autoRefreshEnabled: Bool
153
- public let theme: String
154
- public let displayFormat: String
155
-
156
- public init(
157
- recordID: String = "user-preferences",
158
- version: Int = 1,
159
- modifiedAt: Date = Date(),
160
- lastModifiedDeviceID: String? = nil,
161
- refreshInterval: TimeInterval = 300,
162
- enabledProviders: [String] = [],
163
- notificationsEnabled: Bool = true,
164
- autoRefreshEnabled: Bool = true,
165
- theme: String = "system",
166
- displayFormat: String = "compact")
167
- {
168
- self.recordID = recordID
169
- self.version = version
170
- self.modifiedAt = modifiedAt
171
- self.lastModifiedDeviceID = lastModifiedDeviceID
172
- self.refreshInterval = refreshInterval
173
- self.enabledProviders = enabledProviders
174
- self.notificationsEnabled = notificationsEnabled
175
- self.autoRefreshEnabled = autoRefreshEnabled
176
- self.theme = theme
177
- self.displayFormat = displayFormat
178
- }
179
-
180
- public func toCKRecord() throws -> CKRecord {
181
- let record = CKRecord(recordType: recordType, recordID: CKRecord.ID(recordName: self.recordID))
182
-
183
- record["version"] = self.version as CKRecordValue
184
- record["modifiedAt"] = self.modifiedAt as CKRecordValue
185
- record["lastModifiedDeviceID"] = self.lastModifiedDeviceID as? CKRecordValue
186
- record["refreshInterval"] = self.refreshInterval as CKRecordValue
187
- record["enabledProviders"] = self.enabledProviders as CKRecordValue
188
- record["notificationsEnabled"] = (self.notificationsEnabled ? 1 : 0) as CKRecordValue
189
- record["autoRefreshEnabled"] = (self.autoRefreshEnabled ? 1 : 0) as CKRecordValue
190
- record["theme"] = self.theme as CKRecordValue
191
- record["displayFormat"] = self.displayFormat as CKRecordValue
192
-
193
- return record
194
- }
195
-
196
- public static func fromCKRecord(_ ckRecord: CKRecord) throws -> UserPreferencesSyncRecord {
197
- guard let version = ckRecord["version"] as? Int,
198
- let modifiedAt = ckRecord["modifiedAt"] as? Date,
199
- let refreshInterval = ckRecord["refreshInterval"] as? Double,
200
- let enabledProviders = ckRecord["enabledProviders"] as? [String],
201
- let notificationsEnabled = ckRecord["notificationsEnabled"] as? Int,
202
- let autoRefreshEnabled = ckRecord["autoRefreshEnabled"] as? Int,
203
- let theme = ckRecord["theme"] as? String,
204
- let displayFormat = ckRecord["displayFormat"] as? String
205
- else {
206
- throw SyncError.invalidRecordFormat("Missing required fields in UserPreferences")
207
- }
208
-
209
- return UserPreferencesSyncRecord(
210
- recordID: ckRecord.recordID.recordName,
211
- version: version,
212
- modifiedAt: modifiedAt,
213
- lastModifiedDeviceID: ckRecord["lastModifiedDeviceID"] as? String,
214
- refreshInterval: refreshInterval,
215
- enabledProviders: enabledProviders,
216
- notificationsEnabled: notificationsEnabled == 1,
217
- autoRefreshEnabled: autoRefreshEnabled == 1,
218
- theme: theme,
219
- displayFormat: displayFormat)
220
- }
221
- }
222
-
223
- // MARK: - Alert Configuration Sync Record
224
-
225
- /// Syncable alert configuration record
226
- ///
227
- /// Stores alert thresholds and notification settings that should be
228
- /// consistent across all user devices.
229
- public struct AlertConfigurationSyncRecord: SyncableRecord {
230
- public let recordID: String
231
- public let recordType: String = CloudKitRecordType.alertConfiguration
232
- public let version: Int
233
- public let modifiedAt: Date
234
- public let lastModifiedDeviceID: String?
235
-
236
- // Alert settings
237
- public let providerID: String
238
- public let warningThreshold: Double
239
- public let criticalThreshold: Double
240
- public let notificationChannels: [String]
241
- public let enabled: Bool
242
-
243
- public init(
244
- recordID: String = UUID().uuidString,
245
- version: Int = 1,
246
- modifiedAt: Date = Date(),
247
- lastModifiedDeviceID: String? = nil,
248
- providerID: String,
249
- warningThreshold: Double = 0.75,
250
- criticalThreshold: Double = 0.90,
251
- notificationChannels: [String] = ["system"],
252
- enabled: Bool = true)
253
- {
254
- self.recordID = recordID
255
- self.version = version
256
- self.modifiedAt = modifiedAt
257
- self.lastModifiedDeviceID = lastModifiedDeviceID
258
- self.providerID = providerID
259
- self.warningThreshold = warningThreshold
260
- self.criticalThreshold = criticalThreshold
261
- self.notificationChannels = notificationChannels
262
- self.enabled = enabled
263
- }
264
-
265
- public func toCKRecord() throws -> CKRecord {
266
- let record = CKRecord(recordType: recordType, recordID: CKRecord.ID(recordName: self.recordID))
267
-
268
- record["version"] = self.version as CKRecordValue
269
- record["modifiedAt"] = self.modifiedAt as CKRecordValue
270
- record["lastModifiedDeviceID"] = self.lastModifiedDeviceID as? CKRecordValue
271
- record["providerID"] = self.providerID as CKRecordValue
272
- record["warningThreshold"] = self.warningThreshold as CKRecordValue
273
- record["criticalThreshold"] = self.criticalThreshold as CKRecordValue
274
- record["notificationChannels"] = self.notificationChannels as CKRecordValue
275
- record["enabled"] = (self.enabled ? 1 : 0) as CKRecordValue
276
-
277
- return record
278
- }
279
-
280
- public static func fromCKRecord(_ ckRecord: CKRecord) throws -> AlertConfigurationSyncRecord {
281
- guard let version = ckRecord["version"] as? Int,
282
- let modifiedAt = ckRecord["modifiedAt"] as? Date,
283
- let providerID = ckRecord["providerID"] as? String,
284
- let warningThreshold = ckRecord["warningThreshold"] as? Double,
285
- let criticalThreshold = ckRecord["criticalThreshold"] as? Double,
286
- let notificationChannels = ckRecord["notificationChannels"] as? [String],
287
- let enabled = ckRecord["enabled"] as? Int
288
- else {
289
- throw SyncError.invalidRecordFormat("Missing required fields in AlertConfiguration")
290
- }
291
-
292
- return AlertConfigurationSyncRecord(
293
- recordID: ckRecord.recordID.recordName,
294
- version: version,
295
- modifiedAt: modifiedAt,
296
- lastModifiedDeviceID: ckRecord["lastModifiedDeviceID"] as? String,
297
- providerID: providerID,
298
- warningThreshold: warningThreshold,
299
- criticalThreshold: criticalThreshold,
300
- notificationChannels: notificationChannels,
301
- enabled: enabled == 1)
302
- }
303
- }
304
-
305
- // MARK: - Encryption Helpers
306
-
307
- /// Encrypts a string using AES-GCM encryption
308
- ///
309
- /// - Parameter plaintext: The string to encrypt
310
- /// - Returns: Base64-encoded encrypted string with nonce prepended
311
- /// - Throws: SyncError.encryptionFailed if encryption fails
312
- private func encryptString(_ plaintext: String) throws -> String {
313
- guard let data = plaintext.data(using: .utf8) else {
314
- throw SyncError.encryptionFailed("Failed to convert string to data")
315
- }
316
-
317
- let key = getOrCreateEncryptionKey()
318
- let sealed = try AES.GCM.seal(data, using: key)
319
-
320
- guard let combined = sealed.combined else {
321
- throw SyncError.encryptionFailed("Failed to create sealed box")
322
- }
323
-
324
- return combined.base64EncodedString()
325
- }
326
-
327
- /// Decrypts a string that was encrypted with encryptString
328
- ///
329
- /// - Parameter encrypted: Base64-encoded encrypted string
330
- /// - Returns: Decrypted plaintext string
331
- /// - Throws: SyncError.encryptionFailed if decryption fails
332
- private func decryptString(_ encrypted: String) throws -> String {
333
- guard let combined = Data(base64Encoded: encrypted) else {
334
- throw SyncError.encryptionFailed("Failed to decode base64")
335
- }
336
-
337
- let key = getOrCreateEncryptionKey()
338
- let sealedBox = try AES.GCM.SealedBox(combined: combined)
339
- let decrypted = try AES.GCM.open(sealedBox, using: key)
340
-
341
- guard let plaintext = String(data: decrypted, encoding: .utf8) else {
342
- throw SyncError.encryptionFailed("Failed to convert decrypted data to string")
343
- }
344
-
345
- return plaintext
346
- }
347
-
348
- /// Retrieves or creates an encryption key for sensitive data
349
- ///
350
- /// The key is stored securely in the Keychain and persists across app launches.
351
- ///
352
- /// - Returns: SymmetricKey for AES-GCM encryption
353
- private func getOrCreateEncryptionKey() -> SymmetricKey {
354
- let keychainKey = "com.runic.sync.encryption.key"
355
-
356
- // Try to load existing key from Keychain
357
- if let keyData = loadFromKeychain(key: keychainKey) {
358
- return SymmetricKey(data: keyData)
359
- }
360
-
361
- // Generate new key
362
- let key = SymmetricKey(size: .bits256)
363
- let keyData = key.withUnsafeBytes { Data($0) }
364
-
365
- // Store in Keychain
366
- saveToKeychain(key: keychainKey, data: keyData)
367
-
368
- return key
369
- }
370
-
371
- private func saveToKeychain(key: String, data: Data) {
372
- let query: [String: Any] = [
373
- kSecClass as String: kSecClassGenericPassword,
374
- kSecAttrService as String: "com.sriinnu.athena.Runic",
375
- kSecAttrAccount as String: key,
376
- kSecUseDataProtectionKeychain as String: true,
377
- kSecValueData as String: data,
378
- kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock,
379
- ]
380
- SecItemDelete(query as CFDictionary)
381
- SecItemAdd(query as CFDictionary, nil)
382
- }
383
-
384
- private func loadFromKeychain(key: String) -> Data? {
385
- var query: [String: Any] = [
386
- kSecClass as String: kSecClassGenericPassword,
387
- kSecAttrService as String: "com.sriinnu.athena.Runic",
388
- kSecAttrAccount as String: key,
389
- kSecUseDataProtectionKeychain as String: true,
390
- kSecUseAuthenticationUI as String: "kSecUseAuthenticationUIFail" as CFString,
391
- kSecReturnData as String: true,
392
- ]
393
- let authContext = LAContext()
394
- authContext.interactionNotAllowed = true
395
- query[kSecUseAuthenticationContext as String] = authContext
396
- var result: AnyObject?
397
- let status = SecItemCopyMatching(query as CFDictionary, &result)
398
- if status == errSecInteractionNotAllowed {
399
- return nil
400
- }
401
- return status == errSecSuccess ? result as? Data : nil
402
- }