@sriinnu/runic 2.0.0 → 2.11.1

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 +256 -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,768 +0,0 @@
1
- import CloudKit
2
- import CryptoKit
3
- import Foundation
4
- import LocalAuthentication
5
-
6
- // MARK: - CloudKit Record Type Constants
7
-
8
- extension CloudKitRecordType {
9
- public static let team = "Team"
10
- public static let teamMembership = "TeamMembership"
11
- public static let projectOwnership = "ProjectOwnership"
12
- public static let teamUsageSnapshot = "TeamUsageSnapshot"
13
- }
14
-
15
- // MARK: - CloudKit Custom Zone Configuration
16
-
17
- /// Custom zone for team collaboration data
18
- ///
19
- /// Using a custom zone allows for atomic batch operations and better
20
- /// change tracking for team-related records.
21
- public enum TeamSyncZone {
22
- public static let zoneName = "TeamCollaborationZone"
23
- public static let ownerName = CKCurrentUserDefaultName
24
-
25
- public static var zoneID: CKRecordZone.ID {
26
- CKRecordZone.ID(zoneName: zoneName, ownerName: ownerName)
27
- }
28
-
29
- public static func createZone() -> CKRecordZone {
30
- CKRecordZone(zoneID: self.zoneID)
31
- }
32
- }
33
-
34
- // MARK: - Team Record
35
-
36
- /// Team record for CloudKit synchronization
37
- ///
38
- /// Represents a collaborative team that can share usage quotas and projects.
39
- /// - Record Type: "Team"
40
- /// - Queryable by: ownerUserID
41
- /// - Zone: TeamCollaborationZone (custom zone)
42
- public struct TeamRecord: SyncableRecord {
43
- public let recordID: String
44
- public let recordType: String = CloudKitRecordType.team
45
- public let version: Int
46
- public let modifiedAt: Date
47
- public let lastModifiedDeviceID: String?
48
-
49
- // Team data
50
- public let teamID: String
51
- public let name: String
52
- public let ownerUserID: String
53
- public let totalQuota: Int64
54
- public let createdAt: Date
55
- public let updatedAt: Date
56
-
57
- // Optional metadata
58
- public let description: String?
59
- public let avatarURL: String?
60
- public let isActive: Bool
61
-
62
- public init(
63
- recordID: String = UUID().uuidString,
64
- version: Int = 1,
65
- modifiedAt: Date = Date(),
66
- lastModifiedDeviceID: String? = nil,
67
- teamID: String = UUID().uuidString,
68
- name: String,
69
- ownerUserID: String,
70
- totalQuota: Int64,
71
- createdAt: Date = Date(),
72
- updatedAt: Date = Date(),
73
- description: String? = nil,
74
- avatarURL: String? = nil,
75
- isActive: Bool = true)
76
- {
77
- self.recordID = recordID
78
- self.version = version
79
- self.modifiedAt = modifiedAt
80
- self.lastModifiedDeviceID = lastModifiedDeviceID
81
- self.teamID = teamID
82
- self.name = name
83
- self.ownerUserID = ownerUserID
84
- self.totalQuota = totalQuota
85
- self.createdAt = createdAt
86
- self.updatedAt = updatedAt
87
- self.description = description
88
- self.avatarURL = avatarURL
89
- self.isActive = isActive
90
- }
91
-
92
- public func toCKRecord() throws -> CKRecord {
93
- let zoneID = TeamSyncZone.zoneID
94
- let record = CKRecord(
95
- recordType: recordType,
96
- recordID: CKRecord.ID(recordName: self.recordID, zoneID: zoneID))
97
-
98
- // Sync metadata
99
- record["version"] = self.version as CKRecordValue
100
- record["modifiedAt"] = self.modifiedAt as CKRecordValue
101
- record["lastModifiedDeviceID"] = self.lastModifiedDeviceID as? CKRecordValue
102
-
103
- // Team data
104
- record["teamID"] = self.teamID as CKRecordValue
105
- record["name"] = self.name as CKRecordValue
106
- record["ownerUserID"] = self.ownerUserID as CKRecordValue
107
- record["totalQuota"] = self.totalQuota as CKRecordValue
108
- record["createdAt"] = self.createdAt as CKRecordValue
109
- record["updatedAt"] = self.updatedAt as CKRecordValue
110
- record["isActive"] = (self.isActive ? 1 : 0) as CKRecordValue
111
-
112
- // Optional fields
113
- record["description"] = self.description as? CKRecordValue
114
- record["avatarURL"] = self.avatarURL as? CKRecordValue
115
-
116
- return record
117
- }
118
-
119
- public static func fromCKRecord(_ ckRecord: CKRecord) throws -> TeamRecord {
120
- guard let version = ckRecord["version"] as? Int,
121
- let modifiedAt = ckRecord["modifiedAt"] as? Date,
122
- let teamID = ckRecord["teamID"] as? String,
123
- let name = ckRecord["name"] as? String,
124
- let ownerUserID = ckRecord["ownerUserID"] as? String,
125
- let totalQuota = ckRecord["totalQuota"] as? Int64,
126
- let createdAt = ckRecord["createdAt"] as? Date,
127
- let updatedAt = ckRecord["updatedAt"] as? Date,
128
- let isActiveInt = ckRecord["isActive"] as? Int
129
- else {
130
- throw SyncError.invalidRecordFormat("Missing required fields in Team record")
131
- }
132
-
133
- return TeamRecord(
134
- recordID: ckRecord.recordID.recordName,
135
- version: version,
136
- modifiedAt: modifiedAt,
137
- lastModifiedDeviceID: ckRecord["lastModifiedDeviceID"] as? String,
138
- teamID: teamID,
139
- name: name,
140
- ownerUserID: ownerUserID,
141
- totalQuota: totalQuota,
142
- createdAt: createdAt,
143
- updatedAt: updatedAt,
144
- description: ckRecord["description"] as? String,
145
- avatarURL: ckRecord["avatarURL"] as? String,
146
- isActive: isActiveInt == 1)
147
- }
148
- }
149
-
150
- // MARK: - Team Membership Record
151
-
152
- /// Team membership record for CloudKit synchronization
153
- ///
154
- /// Represents a user's membership in a team with role and quota information.
155
- /// - Record Type: "TeamMembership"
156
- /// - Queryable by: teamID, userID
157
- /// - References: Team record (parent)
158
- /// - Zone: TeamCollaborationZone (custom zone)
159
- public struct TeamMembershipRecord: SyncableRecord {
160
- public let recordID: String
161
- public let recordType: String = CloudKitRecordType.teamMembership
162
- public let version: Int
163
- public let modifiedAt: Date
164
- public let lastModifiedDeviceID: String?
165
-
166
- // Membership data
167
- public let membershipID: String
168
- public let teamID: String
169
- public let userID: String
170
- public let role: TeamRole
171
- public let quotaLimit: Int64?
172
- public let joinedAt: Date
173
-
174
- // Optional metadata
175
- public let email: String?
176
- public let displayName: String?
177
- public let invitedBy: String?
178
- public let acceptedAt: Date?
179
- public let isActive: Bool
180
-
181
- /// Reference to parent team
182
- public let teamRecordName: String
183
-
184
- public enum TeamRole: String, Codable, Sendable {
185
- case owner
186
- case admin
187
- case member
188
- case viewer
189
- }
190
-
191
- public init(
192
- recordID: String = UUID().uuidString,
193
- version: Int = 1,
194
- modifiedAt: Date = Date(),
195
- lastModifiedDeviceID: String? = nil,
196
- membershipID: String = UUID().uuidString,
197
- teamID: String,
198
- userID: String,
199
- role: TeamRole,
200
- quotaLimit: Int64? = nil,
201
- joinedAt: Date = Date(),
202
- email: String? = nil,
203
- displayName: String? = nil,
204
- invitedBy: String? = nil,
205
- acceptedAt: Date? = nil,
206
- isActive: Bool = true,
207
- teamRecordName: String)
208
- {
209
- self.recordID = recordID
210
- self.version = version
211
- self.modifiedAt = modifiedAt
212
- self.lastModifiedDeviceID = lastModifiedDeviceID
213
- self.membershipID = membershipID
214
- self.teamID = teamID
215
- self.userID = userID
216
- self.role = role
217
- self.quotaLimit = quotaLimit
218
- self.joinedAt = joinedAt
219
- self.email = email
220
- self.displayName = displayName
221
- self.invitedBy = invitedBy
222
- self.acceptedAt = acceptedAt
223
- self.isActive = isActive
224
- self.teamRecordName = teamRecordName
225
- }
226
-
227
- public func toCKRecord() throws -> CKRecord {
228
- let zoneID = TeamSyncZone.zoneID
229
- let record = CKRecord(
230
- recordType: recordType,
231
- recordID: CKRecord.ID(recordName: self.recordID, zoneID: zoneID))
232
-
233
- // Sync metadata
234
- record["version"] = self.version as CKRecordValue
235
- record["modifiedAt"] = self.modifiedAt as CKRecordValue
236
- record["lastModifiedDeviceID"] = self.lastModifiedDeviceID as? CKRecordValue
237
-
238
- // Membership data
239
- record["membershipID"] = self.membershipID as CKRecordValue
240
- record["teamID"] = self.teamID as CKRecordValue
241
- record["userID"] = self.userID as CKRecordValue
242
- record["role"] = self.role.rawValue as CKRecordValue
243
- record["quotaLimit"] = self.quotaLimit as? CKRecordValue
244
- record["joinedAt"] = self.joinedAt as CKRecordValue
245
- record["isActive"] = (self.isActive ? 1 : 0) as CKRecordValue
246
-
247
- // Optional encrypted fields
248
- if let email {
249
- let encrypted = try encryptString(email)
250
- record["email"] = encrypted as CKRecordValue
251
- }
252
- record["displayName"] = self.displayName as? CKRecordValue
253
- record["invitedBy"] = self.invitedBy as? CKRecordValue
254
- record["acceptedAt"] = self.acceptedAt as? CKRecordValue
255
-
256
- // Reference to parent team
257
- let teamReference = CKRecord.Reference(
258
- recordID: CKRecord.ID(recordName: self.teamRecordName, zoneID: zoneID),
259
- action: .deleteSelf)
260
- record["teamReference"] = teamReference as CKRecordValue
261
-
262
- return record
263
- }
264
-
265
- public static func fromCKRecord(_ ckRecord: CKRecord) throws -> TeamMembershipRecord {
266
- guard let version = ckRecord["version"] as? Int,
267
- let modifiedAt = ckRecord["modifiedAt"] as? Date,
268
- let membershipID = ckRecord["membershipID"] as? String,
269
- let teamID = ckRecord["teamID"] as? String,
270
- let userID = ckRecord["userID"] as? String,
271
- let roleString = ckRecord["role"] as? String,
272
- let role = TeamRole(rawValue: roleString),
273
- let joinedAt = ckRecord["joinedAt"] as? Date,
274
- let isActiveInt = ckRecord["isActive"] as? Int,
275
- let teamReference = ckRecord["teamReference"] as? CKRecord.Reference
276
- else {
277
- throw SyncError.invalidRecordFormat("Missing required fields in TeamMembership record")
278
- }
279
-
280
- var email: String?
281
- if let encryptedEmail = ckRecord["email"] as? String {
282
- email = try? decryptString(encryptedEmail)
283
- }
284
-
285
- return TeamMembershipRecord(
286
- recordID: ckRecord.recordID.recordName,
287
- version: version,
288
- modifiedAt: modifiedAt,
289
- lastModifiedDeviceID: ckRecord["lastModifiedDeviceID"] as? String,
290
- membershipID: membershipID,
291
- teamID: teamID,
292
- userID: userID,
293
- role: role,
294
- quotaLimit: ckRecord["quotaLimit"] as? Int64,
295
- joinedAt: joinedAt,
296
- email: email,
297
- displayName: ckRecord["displayName"] as? String,
298
- invitedBy: ckRecord["invitedBy"] as? String,
299
- acceptedAt: ckRecord["acceptedAt"] as? Date,
300
- isActive: isActiveInt == 1,
301
- teamRecordName: teamReference.recordID.recordName)
302
- }
303
- }
304
-
305
- // MARK: - Project Ownership Record
306
-
307
- /// Project ownership record for CloudKit synchronization
308
- ///
309
- /// Represents ownership and sharing permissions for a project.
310
- /// - Record Type: "ProjectOwnership"
311
- /// - Queryable by: ownerUserID, teamID, projectID
312
- /// - References: Team record (optional - if team-owned)
313
- /// - Zone: TeamCollaborationZone (custom zone)
314
- public struct ProjectOwnershipRecord: SyncableRecord {
315
- public let recordID: String
316
- public let recordType: String = CloudKitRecordType.projectOwnership
317
- public let version: Int
318
- public let modifiedAt: Date
319
- public let lastModifiedDeviceID: String?
320
-
321
- // Project ownership data
322
- public let projectID: String
323
- public let teamID: String?
324
- public let ownerUserID: String
325
- public let sharedWith: [String]
326
- public let accessLevel: AccessLevel
327
- public let createdAt: Date
328
-
329
- // Optional metadata
330
- public let projectName: String?
331
- public let projectDescription: String?
332
- public let tags: [String]
333
- public let isArchived: Bool
334
-
335
- /// Reference to team (if team-owned)
336
- public let teamRecordName: String?
337
-
338
- public enum AccessLevel: String, Codable, Sendable {
339
- case `private`
340
- case teamReadOnly = "team_read_only"
341
- case teamReadWrite = "team_read_write"
342
- case `public`
343
- }
344
-
345
- public init(
346
- recordID: String = UUID().uuidString,
347
- version: Int = 1,
348
- modifiedAt: Date = Date(),
349
- lastModifiedDeviceID: String? = nil,
350
- projectID: String = UUID().uuidString,
351
- teamID: String? = nil,
352
- ownerUserID: String,
353
- sharedWith: [String] = [],
354
- accessLevel: AccessLevel = .private,
355
- createdAt: Date = Date(),
356
- projectName: String? = nil,
357
- projectDescription: String? = nil,
358
- tags: [String] = [],
359
- isArchived: Bool = false,
360
- teamRecordName: String? = nil)
361
- {
362
- self.recordID = recordID
363
- self.version = version
364
- self.modifiedAt = modifiedAt
365
- self.lastModifiedDeviceID = lastModifiedDeviceID
366
- self.projectID = projectID
367
- self.teamID = teamID
368
- self.ownerUserID = ownerUserID
369
- self.sharedWith = sharedWith
370
- self.accessLevel = accessLevel
371
- self.createdAt = createdAt
372
- self.projectName = projectName
373
- self.projectDescription = projectDescription
374
- self.tags = tags
375
- self.isArchived = isArchived
376
- self.teamRecordName = teamRecordName
377
- }
378
-
379
- public func toCKRecord() throws -> CKRecord {
380
- let zoneID = TeamSyncZone.zoneID
381
- let record = CKRecord(
382
- recordType: recordType,
383
- recordID: CKRecord.ID(recordName: self.recordID, zoneID: zoneID))
384
-
385
- // Sync metadata
386
- record["version"] = self.version as CKRecordValue
387
- record["modifiedAt"] = self.modifiedAt as CKRecordValue
388
- record["lastModifiedDeviceID"] = self.lastModifiedDeviceID as? CKRecordValue
389
-
390
- // Project ownership data
391
- record["projectID"] = self.projectID as CKRecordValue
392
- record["teamID"] = self.teamID as? CKRecordValue
393
- record["ownerUserID"] = self.ownerUserID as CKRecordValue
394
- record["sharedWith"] = self.sharedWith as CKRecordValue
395
- record["accessLevel"] = self.accessLevel.rawValue as CKRecordValue
396
- record["createdAt"] = self.createdAt as CKRecordValue
397
- record["isArchived"] = (self.isArchived ? 1 : 0) as CKRecordValue
398
-
399
- // Optional metadata
400
- record["projectName"] = self.projectName as? CKRecordValue
401
- record["projectDescription"] = self.projectDescription as? CKRecordValue
402
- record["tags"] = self.tags as CKRecordValue
403
-
404
- // Reference to team (if team-owned)
405
- if let teamRecordName {
406
- let teamReference = CKRecord.Reference(
407
- recordID: CKRecord.ID(recordName: teamRecordName, zoneID: zoneID),
408
- action: .none)
409
- record["teamReference"] = teamReference as CKRecordValue
410
- }
411
-
412
- return record
413
- }
414
-
415
- public static func fromCKRecord(_ ckRecord: CKRecord) throws -> ProjectOwnershipRecord {
416
- guard let version = ckRecord["version"] as? Int,
417
- let modifiedAt = ckRecord["modifiedAt"] as? Date,
418
- let projectID = ckRecord["projectID"] as? String,
419
- let ownerUserID = ckRecord["ownerUserID"] as? String,
420
- let sharedWith = ckRecord["sharedWith"] as? [String],
421
- let accessLevelString = ckRecord["accessLevel"] as? String,
422
- let accessLevel = AccessLevel(rawValue: accessLevelString),
423
- let createdAt = ckRecord["createdAt"] as? Date,
424
- let isArchivedInt = ckRecord["isArchived"] as? Int
425
- else {
426
- throw SyncError.invalidRecordFormat("Missing required fields in ProjectOwnership record")
427
- }
428
-
429
- let teamReference = ckRecord["teamReference"] as? CKRecord.Reference
430
-
431
- return ProjectOwnershipRecord(
432
- recordID: ckRecord.recordID.recordName,
433
- version: version,
434
- modifiedAt: modifiedAt,
435
- lastModifiedDeviceID: ckRecord["lastModifiedDeviceID"] as? String,
436
- projectID: projectID,
437
- teamID: ckRecord["teamID"] as? String,
438
- ownerUserID: ownerUserID,
439
- sharedWith: sharedWith,
440
- accessLevel: accessLevel,
441
- createdAt: createdAt,
442
- projectName: ckRecord["projectName"] as? String,
443
- projectDescription: ckRecord["projectDescription"] as? String,
444
- tags: ckRecord["tags"] as? [String] ?? [],
445
- isArchived: isArchivedInt == 1,
446
- teamRecordName: teamReference?.recordID.recordName)
447
- }
448
- }
449
-
450
- // MARK: - Team Usage Snapshot Record
451
-
452
- /// Team usage snapshot record for CloudKit synchronization
453
- ///
454
- /// Aggregates usage data across team members for tracking and quota management.
455
- /// - Record Type: "TeamUsageSnapshot"
456
- /// - Queryable by: teamID, date
457
- /// - References: Team record (parent)
458
- /// - Zone: TeamCollaborationZone (custom zone)
459
- public struct TeamUsageSnapshotRecord: SyncableRecord {
460
- public let recordID: String
461
- public let recordType: String = CloudKitRecordType.teamUsageSnapshot
462
- public let version: Int
463
- public let modifiedAt: Date
464
- public let lastModifiedDeviceID: String?
465
-
466
- // Team usage data
467
- public let teamID: String
468
- public let date: Date
469
- public let totalTokens: Int64
470
- public let totalCost: Double
471
- public let memberUsage: [String: MemberUsageData]
472
- public let quotaUsedPercent: Double
473
-
474
- // Additional metrics
475
- public let primaryProvider: String?
476
- public let mostActiveUser: String?
477
- public let averageTokensPerMember: Double
478
-
479
- /// Reference to parent team
480
- public let teamRecordName: String
481
-
482
- public struct MemberUsageData: Codable, Sendable, Hashable {
483
- public let userID: String
484
- public let tokens: Int64
485
- public let cost: Double
486
- public let requestCount: Int
487
-
488
- public init(userID: String, tokens: Int64, cost: Double, requestCount: Int) {
489
- self.userID = userID
490
- self.tokens = tokens
491
- self.cost = cost
492
- self.requestCount = requestCount
493
- }
494
- }
495
-
496
- public init(
497
- recordID: String = UUID().uuidString,
498
- version: Int = 1,
499
- modifiedAt: Date = Date(),
500
- lastModifiedDeviceID: String? = nil,
501
- teamID: String,
502
- date: Date = Date(),
503
- totalTokens: Int64,
504
- totalCost: Double,
505
- memberUsage: [String: MemberUsageData] = [:],
506
- quotaUsedPercent: Double,
507
- primaryProvider: String? = nil,
508
- mostActiveUser: String? = nil,
509
- averageTokensPerMember: Double = 0.0,
510
- teamRecordName: String)
511
- {
512
- self.recordID = recordID
513
- self.version = version
514
- self.modifiedAt = modifiedAt
515
- self.lastModifiedDeviceID = lastModifiedDeviceID
516
- self.teamID = teamID
517
- self.date = date
518
- self.totalTokens = totalTokens
519
- self.totalCost = totalCost
520
- self.memberUsage = memberUsage
521
- self.quotaUsedPercent = quotaUsedPercent
522
- self.primaryProvider = primaryProvider
523
- self.mostActiveUser = mostActiveUser
524
- self.averageTokensPerMember = averageTokensPerMember
525
- self.teamRecordName = teamRecordName
526
- }
527
-
528
- public func toCKRecord() throws -> CKRecord {
529
- let zoneID = TeamSyncZone.zoneID
530
- let record = CKRecord(
531
- recordType: recordType,
532
- recordID: CKRecord.ID(recordName: self.recordID, zoneID: zoneID))
533
-
534
- // Sync metadata
535
- record["version"] = self.version as CKRecordValue
536
- record["modifiedAt"] = self.modifiedAt as CKRecordValue
537
- record["lastModifiedDeviceID"] = self.lastModifiedDeviceID as? CKRecordValue
538
-
539
- // Team usage data
540
- record["teamID"] = self.teamID as CKRecordValue
541
- record["date"] = self.date as CKRecordValue
542
- record["totalTokens"] = self.totalTokens as CKRecordValue
543
- record["totalCost"] = self.totalCost as CKRecordValue
544
- record["quotaUsedPercent"] = self.quotaUsedPercent as CKRecordValue
545
-
546
- // Encode member usage as JSON
547
- let encoder = JSONEncoder()
548
- let memberUsageData = try encoder.encode(self.memberUsage)
549
- record["memberUsage"] = String(data: memberUsageData, encoding: .utf8) as? CKRecordValue
550
-
551
- // Optional metrics
552
- record["primaryProvider"] = self.primaryProvider as? CKRecordValue
553
- record["mostActiveUser"] = self.mostActiveUser as? CKRecordValue
554
- record["averageTokensPerMember"] = self.averageTokensPerMember as CKRecordValue
555
-
556
- // Reference to parent team
557
- let teamReference = CKRecord.Reference(
558
- recordID: CKRecord.ID(recordName: self.teamRecordName, zoneID: zoneID),
559
- action: .deleteSelf)
560
- record["teamReference"] = teamReference as CKRecordValue
561
-
562
- return record
563
- }
564
-
565
- public static func fromCKRecord(_ ckRecord: CKRecord) throws -> TeamUsageSnapshotRecord {
566
- guard let version = ckRecord["version"] as? Int,
567
- let modifiedAt = ckRecord["modifiedAt"] as? Date,
568
- let teamID = ckRecord["teamID"] as? String,
569
- let date = ckRecord["date"] as? Date,
570
- let totalTokens = ckRecord["totalTokens"] as? Int64,
571
- let totalCost = ckRecord["totalCost"] as? Double,
572
- let quotaUsedPercent = ckRecord["quotaUsedPercent"] as? Double,
573
- let teamReference = ckRecord["teamReference"] as? CKRecord.Reference
574
- else {
575
- throw SyncError.invalidRecordFormat("Missing required fields in TeamUsageSnapshot record")
576
- }
577
-
578
- // Decode member usage from JSON
579
- var memberUsage: [String: MemberUsageData] = [:]
580
- if let memberUsageJSON = ckRecord["memberUsage"] as? String,
581
- let data = memberUsageJSON.data(using: .utf8)
582
- {
583
- let decoder = JSONDecoder()
584
- memberUsage = (try? decoder.decode([String: MemberUsageData].self, from: data)) ?? [:]
585
- }
586
-
587
- return TeamUsageSnapshotRecord(
588
- recordID: ckRecord.recordID.recordName,
589
- version: version,
590
- modifiedAt: modifiedAt,
591
- lastModifiedDeviceID: ckRecord["lastModifiedDeviceID"] as? String,
592
- teamID: teamID,
593
- date: date,
594
- totalTokens: totalTokens,
595
- totalCost: totalCost,
596
- memberUsage: memberUsage,
597
- quotaUsedPercent: quotaUsedPercent,
598
- primaryProvider: ckRecord["primaryProvider"] as? String,
599
- mostActiveUser: ckRecord["mostActiveUser"] as? String,
600
- averageTokensPerMember: ckRecord["averageTokensPerMember"] as? Double ?? 0.0,
601
- teamRecordName: teamReference.recordID.recordName)
602
- }
603
- }
604
-
605
- // MARK: - CloudKit Query Helpers
606
-
607
- /// Helper methods for querying team-related records
608
- public enum TeamRecordQuery {
609
- /// Creates a predicate to query teams by owner
610
- public static func teamsByOwner(_ ownerUserID: String) -> NSPredicate {
611
- NSPredicate(format: "ownerUserID == %@", ownerUserID)
612
- }
613
-
614
- /// Creates a predicate to query memberships by team
615
- public static func membershipsByTeam(_ teamID: String) -> NSPredicate {
616
- NSPredicate(format: "teamID == %@ AND isActive == 1", teamID)
617
- }
618
-
619
- /// Creates a predicate to query memberships by user
620
- public static func membershipsByUser(_ userID: String) -> NSPredicate {
621
- NSPredicate(format: "userID == %@ AND isActive == 1", userID)
622
- }
623
-
624
- /// Creates a predicate to query projects by owner
625
- public static func projectsByOwner(_ ownerUserID: String) -> NSPredicate {
626
- NSPredicate(format: "ownerUserID == %@ AND isArchived == 0", ownerUserID)
627
- }
628
-
629
- /// Creates a predicate to query projects by team
630
- public static func projectsByTeam(_ teamID: String) -> NSPredicate {
631
- NSPredicate(format: "teamID == %@ AND isArchived == 0", teamID)
632
- }
633
-
634
- /// Creates a predicate to query team usage snapshots by date range
635
- public static func teamUsageByDateRange(teamID: String, startDate: Date, endDate: Date) -> NSPredicate {
636
- NSPredicate(
637
- format: "teamID == %@ AND date >= %@ AND date <= %@",
638
- teamID,
639
- startDate as NSDate,
640
- endDate as NSDate)
641
- }
642
-
643
- /// Creates a predicate to query latest team usage
644
- public static func latestTeamUsage(_ teamID: String) -> NSPredicate {
645
- NSPredicate(format: "teamID == %@", teamID)
646
- }
647
- }
648
-
649
- // MARK: - CloudKit Index Configuration
650
-
651
- /// Recommended CloudKit indexes for efficient querying
652
- ///
653
- /// Configure these indexes in CloudKit Dashboard for optimal performance:
654
- ///
655
- /// Team Record:
656
- /// - ownerUserID (Queryable, Sortable)
657
- /// - isActive (Queryable)
658
- /// - createdAt (Sortable)
659
- ///
660
- /// TeamMembership Record:
661
- /// - teamID (Queryable, Sortable)
662
- /// - userID (Queryable, Sortable)
663
- /// - isActive (Queryable)
664
- /// - role (Queryable)
665
- /// - joinedAt (Sortable)
666
- ///
667
- /// ProjectOwnership Record:
668
- /// - ownerUserID (Queryable, Sortable)
669
- /// - teamID (Queryable, Sortable)
670
- /// - projectID (Queryable)
671
- /// - isArchived (Queryable)
672
- /// - accessLevel (Queryable)
673
- /// - createdAt (Sortable)
674
- ///
675
- /// TeamUsageSnapshot Record:
676
- /// - teamID (Queryable, Sortable)
677
- /// - date (Queryable, Sortable)
678
- /// - quotaUsedPercent (Sortable)
679
- public enum TeamRecordIndexes {
680
- // This is a documentation enum - configure actual indexes in CloudKit Dashboard
681
- }
682
-
683
- // MARK: - Encryption Helpers (Team-specific)
684
-
685
- /// Encrypts a string using AES-GCM encryption (team-specific wrapper)
686
- private func encryptString(_ plaintext: String) throws -> String {
687
- guard let data = plaintext.data(using: .utf8) else {
688
- throw SyncError.encryptionFailed("Failed to convert string to data")
689
- }
690
-
691
- let key = getOrCreateEncryptionKey()
692
- let sealed = try AES.GCM.seal(data, using: key)
693
-
694
- guard let combined = sealed.combined else {
695
- throw SyncError.encryptionFailed("Failed to create sealed box")
696
- }
697
-
698
- return combined.base64EncodedString()
699
- }
700
-
701
- /// Decrypts a string that was encrypted with encryptString
702
- private func decryptString(_ encrypted: String) throws -> String {
703
- guard let combined = Data(base64Encoded: encrypted) else {
704
- throw SyncError.encryptionFailed("Failed to decode base64")
705
- }
706
-
707
- let key = getOrCreateEncryptionKey()
708
- let sealedBox = try AES.GCM.SealedBox(combined: combined)
709
- let decrypted = try AES.GCM.open(sealedBox, using: key)
710
-
711
- guard let plaintext = String(data: decrypted, encoding: .utf8) else {
712
- throw SyncError.encryptionFailed("Failed to convert decrypted data to string")
713
- }
714
-
715
- return plaintext
716
- }
717
-
718
- /// Retrieves or creates an encryption key for sensitive data
719
- private func getOrCreateEncryptionKey() -> SymmetricKey {
720
- let keychainKey = "com.runic.sync.team.encryption.key"
721
-
722
- // Try to load existing key from Keychain
723
- if let keyData = loadFromKeychain(key: keychainKey) {
724
- return SymmetricKey(data: keyData)
725
- }
726
-
727
- // Generate new key
728
- let key = SymmetricKey(size: .bits256)
729
- let keyData = key.withUnsafeBytes { Data($0) }
730
-
731
- // Store in Keychain
732
- saveToKeychain(key: keychainKey, data: keyData)
733
-
734
- return key
735
- }
736
-
737
- private func saveToKeychain(key: String, data: Data) {
738
- let query: [String: Any] = [
739
- kSecClass as String: kSecClassGenericPassword,
740
- kSecAttrService as String: "com.sriinnu.athena.Runic",
741
- kSecAttrAccount as String: key,
742
- kSecUseDataProtectionKeychain as String: true,
743
- kSecValueData as String: data,
744
- kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock,
745
- ]
746
- SecItemDelete(query as CFDictionary)
747
- SecItemAdd(query as CFDictionary, nil)
748
- }
749
-
750
- private func loadFromKeychain(key: String) -> Data? {
751
- var query: [String: Any] = [
752
- kSecClass as String: kSecClassGenericPassword,
753
- kSecAttrService as String: "com.sriinnu.athena.Runic",
754
- kSecAttrAccount as String: key,
755
- kSecUseDataProtectionKeychain as String: true,
756
- kSecUseAuthenticationUI as String: "kSecUseAuthenticationUIFail" as CFString,
757
- kSecReturnData as String: true,
758
- ]
759
- let authContext = LAContext()
760
- authContext.interactionNotAllowed = true
761
- query[kSecUseAuthenticationContext as String] = authContext
762
- var result: AnyObject?
763
- let status = SecItemCopyMatching(query as CFDictionary, &result)
764
- if status == errSecInteractionNotAllowed {
765
- return nil
766
- }
767
- return status == errSecSuccess ? result as? Data : nil
768
- }