@sriinnu/runic 1.2.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 (586) hide show
  1. package/CHANGELOG.md +267 -0
  2. package/LICENSE +373 -21
  3. package/README.md +98 -84
  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/iOSUsageStore.swift +0 -192
  55. package/RuniciOS/Views/ProviderDetailView.swift +0 -312
  56. package/RuniciOS/Views/ProviderListView.swift +0 -228
  57. package/RuniciOS/Widgets/LargeWidget.swift +0 -367
  58. package/RuniciOS/Widgets/LiveActivity.swift +0 -342
  59. package/RuniciOS/Widgets/LockScreenWidget.swift +0 -273
  60. package/RuniciOS/Widgets/MediumWidget.swift +0 -370
  61. package/RuniciOS/Widgets/RunicWidget.swift +0 -274
  62. package/RuniciOS/Widgets/SmallWidget.swift +0 -281
  63. package/RuniciOS/Widgets/WidgetModels.swift +0 -285
  64. package/RuniciOS/Widgets/WidgetTimeline.swift +0 -270
  65. package/Scripts/CREATION-SUMMARY.md +0 -367
  66. package/Scripts/DIRECTORY-STRUCTURE.md +0 -358
  67. package/Scripts/GETTING-STARTED-CHECKLIST.md +0 -364
  68. package/Scripts/INDEX.md +0 -365
  69. package/Scripts/QUICK-REFERENCE.md +0 -164
  70. package/Scripts/README-SCRIPTS.md +0 -926
  71. package/Scripts/build-android.sh +0 -526
  72. package/Scripts/build-ios.sh +0 -529
  73. package/Scripts/build-macos.sh +0 -603
  74. package/Scripts/build-windows.sh +0 -504
  75. package/Scripts/build_icon.sh +0 -49
  76. package/Scripts/changelog-to-html.sh +0 -89
  77. package/Scripts/check-release-assets.sh +0 -10
  78. package/Scripts/ci-config.yml +0 -474
  79. package/Scripts/compile_and_run.sh +0 -219
  80. package/Scripts/compile_and_run_adhoc.sh +0 -4
  81. package/Scripts/docs-list.mjs +0 -119
  82. package/Scripts/make_appcast.sh +0 -58
  83. package/Scripts/package_app.sh +0 -409
  84. package/Scripts/release-lib.sh +0 -214
  85. package/Scripts/release.sh +0 -76
  86. package/Scripts/setup-all.sh +0 -387
  87. package/Scripts/setup-ios.sh +0 -404
  88. package/Scripts/setup-react-native.sh +0 -523
  89. package/Scripts/sign-and-notarize.sh +0 -122
  90. package/Scripts/test_live_update.sh +0 -38
  91. package/Scripts/validate_changelog.sh +0 -23
  92. package/Scripts/verify_appcast.sh +0 -92
  93. package/Sources/Runic/About.swift +0 -93
  94. package/Sources/Runic/AppNotifications.swift +0 -115
  95. package/Sources/Runic/Controllers/StatusItemController+Actions.swift +0 -666
  96. package/Sources/Runic/Controllers/StatusItemController+Animation.swift +0 -518
  97. package/Sources/Runic/Controllers/StatusItemController+ChartSubmenus.swift +0 -810
  98. package/Sources/Runic/Controllers/StatusItemController+CustomProviders.swift +0 -87
  99. package/Sources/Runic/Controllers/StatusItemController+Menu.swift +0 -1407
  100. package/Sources/Runic/Controllers/StatusItemController+MenuCards.swift +0 -337
  101. package/Sources/Runic/Controllers/StatusItemController+MenuHelpers.swift +0 -395
  102. package/Sources/Runic/Controllers/StatusItemController.swift +0 -360
  103. package/Sources/Runic/Core/BudgetNotificationManager.swift +0 -80
  104. package/Sources/Runic/Core/Login/ClaudeLoginRunner.swift +0 -103
  105. package/Sources/Runic/Core/Login/CodexLoginRunner.swift +0 -154
  106. package/Sources/Runic/Core/Login/CursorLoginRunner.swift +0 -206
  107. package/Sources/Runic/Core/Login/GeminiLoginRunner.swift +0 -92
  108. package/Sources/Runic/Core/Rendering/IconRenderer.swift +0 -1216
  109. package/Sources/Runic/Core/Rendering/IconView.swift +0 -120
  110. package/Sources/Runic/Core/Rendering/ProviderBrandIcon.swift +0 -71
  111. package/Sources/Runic/Core/RunicAnimation.swift +0 -53
  112. package/Sources/Runic/Core/RunicColors.swift +0 -73
  113. package/Sources/Runic/Core/RunicCornerRadius.swift +0 -15
  114. package/Sources/Runic/Core/RunicSpacing.swift +0 -68
  115. package/Sources/Runic/Core/Stores/AuggieTokenStore.swift +0 -119
  116. package/Sources/Runic/Core/Stores/AzureOpenAITokenStore.swift +0 -119
  117. package/Sources/Runic/Core/Stores/CerebrasTokenStore.swift +0 -119
  118. package/Sources/Runic/Core/Stores/CohereTokenStore.swift +0 -119
  119. package/Sources/Runic/Core/Stores/CopilotTokenStore.swift +0 -119
  120. package/Sources/Runic/Core/Stores/CustomProviderStore.swift +0 -158
  121. package/Sources/Runic/Core/Stores/DeepSeekTokenStore.swift +0 -119
  122. package/Sources/Runic/Core/Stores/FireworksTokenStore.swift +0 -119
  123. package/Sources/Runic/Core/Stores/GroqTokenStore.swift +0 -119
  124. package/Sources/Runic/Core/Stores/KimiTokenStore.swift +0 -119
  125. package/Sources/Runic/Core/Stores/MiniMaxCookieHeaderStore.swift +0 -119
  126. package/Sources/Runic/Core/Stores/MiniMaxGroupIDStore.swift +0 -119
  127. package/Sources/Runic/Core/Stores/MiniMaxTokenStore.swift +0 -119
  128. package/Sources/Runic/Core/Stores/MistralTokenStore.swift +0 -119
  129. package/Sources/Runic/Core/Stores/OpenRouterTokenStore.swift +0 -119
  130. package/Sources/Runic/Core/Stores/PerplexityTokenStore.swift +0 -119
  131. package/Sources/Runic/Core/Stores/ProviderToggleStore.swift +0 -30
  132. package/Sources/Runic/Core/Stores/QwenTokenStore.swift +0 -119
  133. package/Sources/Runic/Core/Stores/SambaNovaTokenStore.swift +0 -119
  134. package/Sources/Runic/Core/Stores/SettingsStore.swift +0 -1711
  135. package/Sources/Runic/Core/Stores/TogetherTokenStore.swift +0 -119
  136. package/Sources/Runic/Core/Stores/UsageStore+Accessors.swift +0 -20
  137. package/Sources/Runic/Core/Stores/UsageStore+Status.swift +0 -189
  138. package/Sources/Runic/Core/Stores/UsageStore+TokenCost.swift +0 -33
  139. package/Sources/Runic/Core/Stores/UsageStore+WidgetSnapshot.swift +0 -67
  140. package/Sources/Runic/Core/Stores/UsageStore.swift +0 -3605
  141. package/Sources/Runic/Core/Stores/XAITokenStore.swift +0 -119
  142. package/Sources/Runic/Core/Stores/ZaiTokenStore.swift +0 -118
  143. package/Sources/Runic/Core/UsageExporter.swift +0 -193
  144. package/Sources/Runic/Date+RelativeDescription.swift +0 -21
  145. package/Sources/Runic/HiddenWindowView.swift +0 -32
  146. package/Sources/Runic/InstallOrigin.swift +0 -9
  147. package/Sources/Runic/KeyboardShortcuts+Names.swift +0 -6
  148. package/Sources/Runic/MouseLocationReader.swift +0 -65
  149. package/Sources/Runic/Notifications+Runic.swift +0 -6
  150. package/Sources/Runic/OpenAICreditsPurchaseWindowController.swift +0 -503
  151. package/Sources/Runic/ProviderRegistry.swift +0 -100
  152. package/Sources/Runic/ProviderSwitcherButtons.swift +0 -267
  153. package/Sources/Runic/Providers/Antigravity/AntigravityLoginFlow.swift +0 -11
  154. package/Sources/Runic/Providers/Antigravity/AntigravityProviderImplementation.swift +0 -14
  155. package/Sources/Runic/Providers/Auggie/AuggieProviderImplementation.swift +0 -24
  156. package/Sources/Runic/Providers/Azure/AzureProviderImplementation.swift +0 -52
  157. package/Sources/Runic/Providers/Bedrock/BedrockProviderImplementation.swift +0 -42
  158. package/Sources/Runic/Providers/Cerebras/CerebrasProviderImplementation.swift +0 -24
  159. package/Sources/Runic/Providers/Claude/ClaudeLoginFlow.swift +0 -26
  160. package/Sources/Runic/Providers/Claude/ClaudeProviderImplementation.swift +0 -14
  161. package/Sources/Runic/Providers/Codex/CodexLoginFlow.swift +0 -18
  162. package/Sources/Runic/Providers/Codex/CodexProviderImplementation.swift +0 -15
  163. package/Sources/Runic/Providers/Cohere/CohereProviderImplementation.swift +0 -24
  164. package/Sources/Runic/Providers/Copilot/CopilotLoginFlow.swift +0 -193
  165. package/Sources/Runic/Providers/Copilot/CopilotProviderImplementation.swift +0 -110
  166. package/Sources/Runic/Providers/Cursor/CursorLoginFlow.swift +0 -28
  167. package/Sources/Runic/Providers/Cursor/CursorProviderImplementation.swift +0 -15
  168. package/Sources/Runic/Providers/DeepSeek/DeepSeekProviderImplementation.swift +0 -24
  169. package/Sources/Runic/Providers/Factory/FactoryLoginFlow.swift +0 -12
  170. package/Sources/Runic/Providers/Factory/FactoryProviderImplementation.swift +0 -15
  171. package/Sources/Runic/Providers/Fireworks/FireworksProviderImplementation.swift +0 -24
  172. package/Sources/Runic/Providers/Gemini/GeminiLoginFlow.swift +0 -20
  173. package/Sources/Runic/Providers/Gemini/GeminiProviderImplementation.swift +0 -15
  174. package/Sources/Runic/Providers/Groq/GroqProviderImplementation.swift +0 -24
  175. package/Sources/Runic/Providers/Kimi/KimiProviderImplementation.swift +0 -24
  176. package/Sources/Runic/Providers/MiniMax/MiniMaxProviderImplementation.swift +0 -32
  177. package/Sources/Runic/Providers/Mistral/MistralProviderImplementation.swift +0 -24
  178. package/Sources/Runic/Providers/OpenRouter/OpenRouterProviderImplementation.swift +0 -24
  179. package/Sources/Runic/Providers/Perplexity/PerplexityProviderImplementation.swift +0 -24
  180. package/Sources/Runic/Providers/SambaNova/SambaNovaProviderImplementation.swift +0 -24
  181. package/Sources/Runic/Providers/Shared/ProviderCatalog.swift +0 -15
  182. package/Sources/Runic/Providers/Shared/ProviderImplementation.swift +0 -48
  183. package/Sources/Runic/Providers/Shared/ProviderImplementationRegistry.swift +0 -66
  184. package/Sources/Runic/Providers/Shared/ProviderLoginFlow.swift +0 -12
  185. package/Sources/Runic/Providers/Shared/ProviderSettingsDescriptors.swift +0 -99
  186. package/Sources/Runic/Providers/Shared/SystemSettingsLinks.swift +0 -18
  187. package/Sources/Runic/Providers/Together/TogetherProviderImplementation.swift +0 -24
  188. package/Sources/Runic/Providers/XAI/XAIProviderImplementation.swift +0 -24
  189. package/Sources/Runic/Providers/Zai/ZaiProviderImplementation.swift +0 -24
  190. package/Sources/Runic/Resources/ProviderIcon-antigravity.svg +0 -2
  191. package/Sources/Runic/Resources/ProviderIcon-auggie.svg +0 -3
  192. package/Sources/Runic/Resources/ProviderIcon-azure.svg +0 -5
  193. package/Sources/Runic/Resources/ProviderIcon-bedrock.svg +0 -7
  194. package/Sources/Runic/Resources/ProviderIcon-cerebras.svg +0 -3
  195. package/Sources/Runic/Resources/ProviderIcon-claude.svg +0 -1
  196. package/Sources/Runic/Resources/ProviderIcon-codex.svg +0 -1
  197. package/Sources/Runic/Resources/ProviderIcon-cohere.svg +0 -3
  198. package/Sources/Runic/Resources/ProviderIcon-copilot.svg +0 -1
  199. package/Sources/Runic/Resources/ProviderIcon-cursor.svg +0 -3
  200. package/Sources/Runic/Resources/ProviderIcon-deepseek.svg +0 -4
  201. package/Sources/Runic/Resources/ProviderIcon-factory.svg +0 -3
  202. package/Sources/Runic/Resources/ProviderIcon-fireworks.svg +0 -3
  203. package/Sources/Runic/Resources/ProviderIcon-gemini.svg +0 -1
  204. package/Sources/Runic/Resources/ProviderIcon-groq.svg +0 -1
  205. package/Sources/Runic/Resources/ProviderIcon-kimi.svg +0 -4
  206. package/Sources/Runic/Resources/ProviderIcon-minimax.svg +0 -1
  207. package/Sources/Runic/Resources/ProviderIcon-mistral.svg +0 -5
  208. package/Sources/Runic/Resources/ProviderIcon-openrouter.svg +0 -7
  209. package/Sources/Runic/Resources/ProviderIcon-perplexity.svg +0 -4
  210. package/Sources/Runic/Resources/ProviderIcon-qwen.svg +0 -9
  211. package/Sources/Runic/Resources/ProviderIcon-sambanova.svg +0 -4
  212. package/Sources/Runic/Resources/ProviderIcon-together.svg +0 -5
  213. package/Sources/Runic/Resources/ProviderIcon-vertexai.svg +0 -17
  214. package/Sources/Runic/Resources/ProviderIcon-xai.svg +0 -3
  215. package/Sources/Runic/Resources/ProviderIcon-zai.svg +0 -5
  216. package/Sources/Runic/Resources/RunicMenubarIcon.svg +0 -7
  217. package/Sources/Runic/Resources/provider-context-windows.json +0 -20
  218. package/Sources/Runic/RunicApp.swift +0 -357
  219. package/Sources/Runic/SessionQuotaNotifications.swift +0 -58
  220. package/Sources/Runic/UsagePaceText.swift +0 -52
  221. package/Sources/Runic/UsageProgressBar.swift +0 -224
  222. package/Sources/Runic/Utilities/DisplayLink.swift +0 -96
  223. package/Sources/Runic/Utilities/LoadingPattern.swift +0 -60
  224. package/Sources/Runic/Utilities/PerformanceConstants.swift +0 -85
  225. package/Sources/Runic/Views/Menu/AlertsMenuView.swift +0 -256
  226. package/Sources/Runic/Views/Menu/ChartPanelStyle.swift +0 -22
  227. package/Sources/Runic/Views/Menu/CostComparativeChartMenuView.swift +0 -275
  228. package/Sources/Runic/Views/Menu/CostHistoryChartMenuView.swift +0 -377
  229. package/Sources/Runic/Views/Menu/CreditsHistoryChartMenuView.swift +0 -312
  230. package/Sources/Runic/Views/Menu/EfficiencyMetricsMenuView.swift +0 -312
  231. package/Sources/Runic/Views/Menu/HeroStatCardsMenuView.swift +0 -228
  232. package/Sources/Runic/Views/Menu/HourlyActivityChartMenuView.swift +0 -228
  233. package/Sources/Runic/Views/Menu/InlineUsageChartView.swift +0 -155
  234. package/Sources/Runic/Views/Menu/MenuCardEntranceModifier.swift +0 -64
  235. package/Sources/Runic/Views/Menu/MenuCardSidebarView.swift +0 -268
  236. package/Sources/Runic/Views/Menu/MenuCardSkeletonView.swift +0 -104
  237. package/Sources/Runic/Views/Menu/MenuCardView.swift +0 -1900
  238. package/Sources/Runic/Views/Menu/MenuContent.swift +0 -150
  239. package/Sources/Runic/Views/Menu/MenuDescriptor.swift +0 -369
  240. package/Sources/Runic/Views/Menu/MenuHighlightStyle.swift +0 -42
  241. package/Sources/Runic/Views/Menu/ModelBreakdownMenuView.swift +0 -235
  242. package/Sources/Runic/Views/Menu/OverviewMenuView.swift +0 -278
  243. package/Sources/Runic/Views/Menu/ProjectBreakdownMenuView.swift +0 -209
  244. package/Sources/Runic/Views/Menu/ProjectBudgetMenuView.swift +0 -220
  245. package/Sources/Runic/Views/Menu/ProviderTabBarView.swift +0 -88
  246. package/Sources/Runic/Views/Menu/SubscriptionUtilizationChartMenuView.swift +0 -201
  247. package/Sources/Runic/Views/Menu/UsageBreakdownChartMenuView.swift +0 -398
  248. package/Sources/Runic/Views/Menu/UsageHeatmapMenuView.swift +0 -232
  249. package/Sources/Runic/Views/Menu/UsageTimelineChartMenuView.swift +0 -364
  250. package/Sources/Runic/Views/Menu/UsageWindowComparisonChartMenuView.swift +0 -190
  251. package/Sources/Runic/Views/Menu/WeeklyActivityChartMenuView.swift +0 -132
  252. package/Sources/Runic/Views/Performance/PerformanceDashboardView.swift +0 -618
  253. package/Sources/Runic/Views/Preferences/LiquidComponents.swift +0 -305
  254. package/Sources/Runic/Views/Preferences/PreferencesAboutPane.swift +0 -271
  255. package/Sources/Runic/Views/Preferences/PreferencesAdvancedPane.swift +0 -268
  256. package/Sources/Runic/Views/Preferences/PreferencesAlertsPane.swift +0 -422
  257. package/Sources/Runic/Views/Preferences/PreferencesAnalyticsPane.swift +0 -641
  258. package/Sources/Runic/Views/Preferences/PreferencesBudgetsPane.swift +0 -344
  259. package/Sources/Runic/Views/Preferences/PreferencesComponents.swift +0 -230
  260. package/Sources/Runic/Views/Preferences/PreferencesCustomProvidersPane.swift +0 -322
  261. package/Sources/Runic/Views/Preferences/PreferencesDebugPane.swift +0 -469
  262. package/Sources/Runic/Views/Preferences/PreferencesGeneralPane.swift +0 -231
  263. package/Sources/Runic/Views/Preferences/PreferencesHelpPane.swift +0 -50
  264. package/Sources/Runic/Views/Preferences/PreferencesIntegrationsPane.swift +0 -567
  265. package/Sources/Runic/Views/Preferences/PreferencesPerformancePane.swift +0 -288
  266. package/Sources/Runic/Views/Preferences/PreferencesProvidersPane.swift +0 -3435
  267. package/Sources/Runic/Views/Preferences/PreferencesSelection.swift +0 -25
  268. package/Sources/Runic/Views/Preferences/PreferencesSyncPane.swift +0 -59
  269. package/Sources/Runic/Views/Preferences/PreferencesView.swift +0 -206
  270. package/Sources/Runic/Views/Rating/QualityRatingView.swift +0 -238
  271. package/Sources/Runic/Views/Team/TeamDashboardView.swift +0 -371
  272. package/Sources/Runic/Views/Team/TeamInviteSheet.swift +0 -175
  273. package/Sources/Runic/Views/Team/TeamManagementView.swift +0 -761
  274. package/Sources/Runic/Views/Team/TeamMemberRow.swift +0 -181
  275. package/Sources/RunicCLI/CLIEntry.swift +0 -942
  276. package/Sources/RunicCLI/CLIRenderer.swift +0 -87
  277. package/Sources/RunicCLI/Commands/EnhancedUsageCommand.swift +0 -588
  278. package/Sources/RunicCLI/Commands/ModelsCommand.swift +0 -362
  279. package/Sources/RunicCLI/Commands/ProjectsCommand.swift +0 -439
  280. package/Sources/RunicCLI/Commands/ResetCommand.swift +0 -429
  281. package/Sources/RunicCLI/Commands/UsageLedgerSourceFactory.swift +0 -168
  282. package/Sources/RunicClaudeWatchdog/main.swift +0 -122
  283. package/Sources/RunicClaudeWebProbe/main.swift +0 -62
  284. package/Sources/RunicCore/AlertRuleStore.swift +0 -187
  285. package/Sources/RunicCore/BrowserCookieImportOrder.swift +0 -25
  286. package/Sources/RunicCore/CopilotUsageModels.swift +0 -84
  287. package/Sources/RunicCore/CostUsageFetcher.swift +0 -119
  288. package/Sources/RunicCore/CostUsageModels.swift +0 -479
  289. package/Sources/RunicCore/CreditsModels.swift +0 -50
  290. package/Sources/RunicCore/CustomProviders/CustomProviderModels.swift +0 -269
  291. package/Sources/RunicCore/CustomProviders/GenericProviderFetcher.swift +0 -633
  292. package/Sources/RunicCore/CustomProviders/ProviderTemplates.swift +0 -500
  293. package/Sources/RunicCore/Host/PTY/TTYCommandRunner.swift +0 -679
  294. package/Sources/RunicCore/Host/Process/SubprocessRunner.swift +0 -135
  295. package/Sources/RunicCore/Integrations/GitHubIntegration.swift +0 -173
  296. package/Sources/RunicCore/Logging/JSONStderrLogHandler.swift +0 -79
  297. package/Sources/RunicCore/Logging/OSLogLogHandler.swift +0 -86
  298. package/Sources/RunicCore/Logging/RunicLog.swift +0 -123
  299. package/Sources/RunicCore/Models/EnhancedUsageModels.swift +0 -371
  300. package/Sources/RunicCore/OpenAIDashboardModels.swift +0 -210
  301. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardBrowserCookieImporter.swift +0 -676
  302. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardFetcher.swift +0 -492
  303. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardNavigationDelegate.swift +0 -51
  304. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardParser.swift +0 -483
  305. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardScrapeScript.swift +0 -558
  306. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardWebViewCache.swift +0 -204
  307. package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardWebsiteDataStore.swift +0 -78
  308. package/Sources/RunicCore/PathEnvironment.swift +0 -482
  309. package/Sources/RunicCore/Performance/PerformanceModels.swift +0 -371
  310. package/Sources/RunicCore/Performance/PerformanceStorageImpl.swift +0 -409
  311. package/Sources/RunicCore/Policy/UsagePolicyEngine.swift +0 -178
  312. package/Sources/RunicCore/ProjectBudgetStore.swift +0 -99
  313. package/Sources/RunicCore/ProviderCostSnapshot.swift +0 -29
  314. package/Sources/RunicCore/Providers/Antigravity/AntigravityProviderDescriptor.swift +0 -66
  315. package/Sources/RunicCore/Providers/Antigravity/AntigravityStatusProbe.swift +0 -685
  316. package/Sources/RunicCore/Providers/Auggie/AuggieProviderDescriptor.swift +0 -83
  317. package/Sources/RunicCore/Providers/Auggie/AuggieUsageFetcher.swift +0 -142
  318. package/Sources/RunicCore/Providers/Azure/AzureProviderDescriptor.swift +0 -141
  319. package/Sources/RunicCore/Providers/Azure/AzureUsageFetcher.swift +0 -188
  320. package/Sources/RunicCore/Providers/Bedrock/BedrockProviderDescriptor.swift +0 -126
  321. package/Sources/RunicCore/Providers/Bedrock/BedrockUsageFetcher.swift +0 -168
  322. package/Sources/RunicCore/Providers/Cerebras/CerebrasProviderDescriptor.swift +0 -84
  323. package/Sources/RunicCore/Providers/Cerebras/CerebrasUsageFetcher.swift +0 -75
  324. package/Sources/RunicCore/Providers/Claude/ClaudeCLISession.swift +0 -332
  325. package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthCredentials.swift +0 -180
  326. package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthUsageFetcher.swift +0 -137
  327. package/Sources/RunicCore/Providers/Claude/ClaudeProviderDescriptor.swift +0 -207
  328. package/Sources/RunicCore/Providers/Claude/ClaudeStatusProbe.swift +0 -654
  329. package/Sources/RunicCore/Providers/Claude/ClaudeUsageDataSource.swift +0 -28
  330. package/Sources/RunicCore/Providers/Claude/ClaudeUsageFetcher.swift +0 -480
  331. package/Sources/RunicCore/Providers/Claude/ClaudeWeb/ClaudeWebAPIFetcher.swift +0 -780
  332. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthCredentials.swift +0 -147
  333. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthUsageFetcher.swift +0 -280
  334. package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexTokenRefresher.swift +0 -100
  335. package/Sources/RunicCore/Providers/Codex/CodexProviderDescriptor.swift +0 -243
  336. package/Sources/RunicCore/Providers/Codex/CodexStatusProbe.swift +0 -125
  337. package/Sources/RunicCore/Providers/Codex/CodexUsageDataSource.swift +0 -24
  338. package/Sources/RunicCore/Providers/Codex/CodexWebDashboardStrategy.swift +0 -181
  339. package/Sources/RunicCore/Providers/Cohere/CohereProviderDescriptor.swift +0 -83
  340. package/Sources/RunicCore/Providers/Cohere/CohereUsageFetcher.swift +0 -85
  341. package/Sources/RunicCore/Providers/Copilot/CopilotDeviceFlow.swift +0 -123
  342. package/Sources/RunicCore/Providers/Copilot/CopilotGitHubCLITokenReader.swift +0 -114
  343. package/Sources/RunicCore/Providers/Copilot/CopilotProviderDescriptor.swift +0 -100
  344. package/Sources/RunicCore/Providers/Copilot/CopilotUsageFetcher.swift +0 -291
  345. package/Sources/RunicCore/Providers/Copilot/CopilotVSCodeTokenReader.swift +0 -386
  346. package/Sources/RunicCore/Providers/Cursor/CursorProviderDescriptor.swift +0 -65
  347. package/Sources/RunicCore/Providers/Cursor/CursorStatusProbe.swift +0 -595
  348. package/Sources/RunicCore/Providers/DeepSeek/DeepSeekProviderDescriptor.swift +0 -85
  349. package/Sources/RunicCore/Providers/DeepSeek/DeepSeekUsageFetcher.swift +0 -108
  350. package/Sources/RunicCore/Providers/Factory/FactoryLocalStorageImporter.swift +0 -398
  351. package/Sources/RunicCore/Providers/Factory/FactoryProviderDescriptor.swift +0 -65
  352. package/Sources/RunicCore/Providers/Factory/FactoryStatusProbe.swift +0 -1276
  353. package/Sources/RunicCore/Providers/Fireworks/FireworksProviderDescriptor.swift +0 -84
  354. package/Sources/RunicCore/Providers/Fireworks/FireworksUsageFetcher.swift +0 -75
  355. package/Sources/RunicCore/Providers/Gemini/GeminiProviderDescriptor.swift +0 -65
  356. package/Sources/RunicCore/Providers/Gemini/GeminiStatusProbe.swift +0 -836
  357. package/Sources/RunicCore/Providers/Groq/GroqProviderDescriptor.swift +0 -83
  358. package/Sources/RunicCore/Providers/Groq/GroqUsageFetcher.swift +0 -71
  359. package/Sources/RunicCore/Providers/Kimi/KimiProviderDescriptor.swift +0 -83
  360. package/Sources/RunicCore/Providers/Kimi/KimiUsageFetcher.swift +0 -77
  361. package/Sources/RunicCore/Providers/MiniMax/MiniMaxProviderDescriptor.swift +0 -92
  362. package/Sources/RunicCore/Providers/MiniMax/MiniMaxSettingsReader.swift +0 -54
  363. package/Sources/RunicCore/Providers/MiniMax/MiniMaxUsageFetcher.swift +0 -168
  364. package/Sources/RunicCore/Providers/MiniMax/MiniMaxWebUsageFetcher.swift +0 -911
  365. package/Sources/RunicCore/Providers/Mistral/MistralProviderDescriptor.swift +0 -84
  366. package/Sources/RunicCore/Providers/Mistral/MistralUsageFetcher.swift +0 -75
  367. package/Sources/RunicCore/Providers/OpenRouter/OpenRouterProviderDescriptor.swift +0 -87
  368. package/Sources/RunicCore/Providers/OpenRouter/OpenRouterUsageFetcher.swift +0 -203
  369. package/Sources/RunicCore/Providers/Perplexity/PerplexityProviderDescriptor.swift +0 -84
  370. package/Sources/RunicCore/Providers/Perplexity/PerplexityUsageFetcher.swift +0 -75
  371. package/Sources/RunicCore/Providers/ProviderBranding.swift +0 -25
  372. package/Sources/RunicCore/Providers/ProviderCLIConfig.swift +0 -17
  373. package/Sources/RunicCore/Providers/ProviderDescriptor.swift +0 -129
  374. package/Sources/RunicCore/Providers/ProviderFetchPlan.swift +0 -263
  375. package/Sources/RunicCore/Providers/ProviderSettingsSnapshot.swift +0 -98
  376. package/Sources/RunicCore/Providers/ProviderTokenResolver.swift +0 -501
  377. package/Sources/RunicCore/Providers/ProviderVersionDetector.swift +0 -68
  378. package/Sources/RunicCore/Providers/Providers.swift +0 -184
  379. package/Sources/RunicCore/Providers/Qwen/QwenProviderDescriptor.swift +0 -84
  380. package/Sources/RunicCore/Providers/Qwen/QwenSettingsReader.swift +0 -30
  381. package/Sources/RunicCore/Providers/Qwen/QwenUsageStats.swift +0 -315
  382. package/Sources/RunicCore/Providers/SambaNova/SambaNovaProviderDescriptor.swift +0 -84
  383. package/Sources/RunicCore/Providers/SambaNova/SambaNovaUsageFetcher.swift +0 -75
  384. package/Sources/RunicCore/Providers/Together/TogetherProviderDescriptor.swift +0 -83
  385. package/Sources/RunicCore/Providers/Together/TogetherUsageFetcher.swift +0 -75
  386. package/Sources/RunicCore/Providers/VertexAI/VertexAIProviderDescriptor.swift +0 -123
  387. package/Sources/RunicCore/Providers/VertexAI/VertexAISettingsReader.swift +0 -48
  388. package/Sources/RunicCore/Providers/VertexAI/VertexAIUsageFetcher.swift +0 -144
  389. package/Sources/RunicCore/Providers/XAI/XAIProviderDescriptor.swift +0 -83
  390. package/Sources/RunicCore/Providers/XAI/XAIUsageFetcher.swift +0 -75
  391. package/Sources/RunicCore/Providers/Zai/ZaiProviderDescriptor.swift +0 -72
  392. package/Sources/RunicCore/Providers/Zai/ZaiSettingsReader.swift +0 -41
  393. package/Sources/RunicCore/Providers/Zai/ZaiUsageStats.swift +0 -718
  394. package/Sources/RunicCore/Sync/BackgroundSyncManager.swift +0 -385
  395. package/Sources/RunicCore/Sync/SyncConflictResolver.swift +0 -310
  396. package/Sources/RunicCore/Sync/SyncProtocol.swift +0 -288
  397. package/Sources/RunicCore/Sync/SyncRecord.swift +0 -405
  398. package/Sources/RunicCore/Sync/SyncUsageExample.swift +0 -294
  399. package/Sources/RunicCore/Sync/TeamSyncRecords.swift +0 -775
  400. package/Sources/RunicCore/Sync/iCloudSyncEngine.swift +0 -333
  401. package/Sources/RunicCore/Team/TeamModels.swift +0 -583
  402. package/Sources/RunicCore/Team/TeamShowbackExporter.swift +0 -495
  403. package/Sources/RunicCore/Team/TeamStore.swift +0 -792
  404. package/Sources/RunicCore/TextParsing.swift +0 -55
  405. package/Sources/RunicCore/UsageFetcher.swift +0 -694
  406. package/Sources/RunicCore/UsageFormatter.swift +0 -410
  407. package/Sources/RunicCore/UsageLedger/ClaudeUsageLogSource.swift +0 -427
  408. package/Sources/RunicCore/UsageLedger/CodexUsageLogSource.swift +0 -494
  409. package/Sources/RunicCore/UsageLedger/LedgerCache.swift +0 -158
  410. package/Sources/RunicCore/UsageLedger/OTelGenAILedgerAdapter.swift +0 -550
  411. package/Sources/RunicCore/UsageLedger/UsageLedger.swift +0 -29
  412. package/Sources/RunicCore/UsageLedger/UsageLedgerAggregator.swift +0 -660
  413. package/Sources/RunicCore/UsageLedger/UsageLedgerInsightsAdvisor.swift +0 -209
  414. package/Sources/RunicCore/UsageLedger/UsageLedgerModels.swift +0 -417
  415. package/Sources/RunicCore/UsageLedger/UsageLedgerProjectIdentity.swift +0 -245
  416. package/Sources/RunicCore/UsagePace.swift +0 -81
  417. package/Sources/RunicCore/Vendored/CostUsage/CostUsageCache.swift +0 -73
  418. package/Sources/RunicCore/Vendored/CostUsage/CostUsageJsonl.swift +0 -74
  419. package/Sources/RunicCore/Vendored/CostUsage/CostUsagePricing.swift +0 -208
  420. package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner+Claude.swift +0 -455
  421. package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner+Timestamp.swift +0 -132
  422. package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner.swift +0 -589
  423. package/Sources/RunicCore/WidgetSnapshot.swift +0 -183
  424. package/Sources/RunicMacroSupport/ProviderRegistrationMacros.swift +0 -14
  425. package/Sources/RunicMacros/ProviderRegistrationMacros.swift +0 -216
  426. package/Sources/RunicWidget/RunicWidgetBundle.swift +0 -79
  427. package/Sources/RunicWidget/RunicWidgetProvider.swift +0 -283
  428. package/Sources/RunicWidget/RunicWidgetViews.swift +0 -680
  429. package/Tests/RunicTests/AntigravityStatusProbeTests.swift +0 -50
  430. package/Tests/RunicTests/AppDelegateTests.swift +0 -43
  431. package/Tests/RunicTests/BrowserCookieOrderLabelTests.swift +0 -22
  432. package/Tests/RunicTests/CLIArgumentParsingTests.swift +0 -70
  433. package/Tests/RunicTests/CLICostTests.swift +0 -65
  434. package/Tests/RunicTests/CLIProviderSelectionTests.swift +0 -22
  435. package/Tests/RunicTests/CLISnapshotTests.swift +0 -72
  436. package/Tests/RunicTests/CLIWebFallbackTests.swift +0 -58
  437. package/Tests/RunicTests/ClaudeOAuthTests.swift +0 -164
  438. package/Tests/RunicTests/ClaudeResilienceTests.swift +0 -30
  439. package/Tests/RunicTests/ClaudeUsageTests.swift +0 -370
  440. package/Tests/RunicTests/CodexOAuthTests.swift +0 -122
  441. package/Tests/RunicTests/CodexUsageLogSourceTests.swift +0 -82
  442. package/Tests/RunicTests/CopilotTokenResolverTests.swift +0 -75
  443. package/Tests/RunicTests/CopilotVSCodeTokenReaderTests.swift +0 -75
  444. package/Tests/RunicTests/CostUsageDecodingTests.swift +0 -394
  445. package/Tests/RunicTests/CostUsagePricingTests.swift +0 -50
  446. package/Tests/RunicTests/CostUsageScannerTests.swift +0 -700
  447. package/Tests/RunicTests/CursorStatusProbeTests.swift +0 -323
  448. package/Tests/RunicTests/FactoryStatusProbeTests.swift +0 -69
  449. package/Tests/RunicTests/GeminiAPITestHelpers.swift +0 -94
  450. package/Tests/RunicTests/GeminiLoginAlertTests.swift +0 -28
  451. package/Tests/RunicTests/GeminiStatusProbeAPITests.swift +0 -283
  452. package/Tests/RunicTests/GeminiStatusProbePlanTests.swift +0 -279
  453. package/Tests/RunicTests/GeminiStatusProbeTests.swift +0 -233
  454. package/Tests/RunicTests/GeminiTestEnvironment.swift +0 -87
  455. package/Tests/RunicTests/GoogleWorkspaceStatusTests.swift +0 -73
  456. package/Tests/RunicTests/InstallOriginTests.swift +0 -18
  457. package/Tests/RunicTests/KeyboardShortcutsBundleTests.swift +0 -9
  458. package/Tests/RunicTests/LiveAccountTests.swift +0 -24
  459. package/Tests/RunicTests/LoadingPatternTests.swift +0 -35
  460. package/Tests/RunicTests/MenuCardModelTests.swift +0 -545
  461. package/Tests/RunicTests/MiniMaxCookieHeaderStoreTestSupport.swift +0 -8
  462. package/Tests/RunicTests/MiniMaxGroupIDStoreTestSupport.swift +0 -8
  463. package/Tests/RunicTests/MiniMaxParsingTests.swift +0 -68
  464. package/Tests/RunicTests/MiniMaxTokenStoreTestSupport.swift +0 -8
  465. package/Tests/RunicTests/OTelGenAILedgerAdapterTests.swift +0 -112
  466. package/Tests/RunicTests/OpenAIDashboardBrowserCookieImporterTests.swift +0 -17
  467. package/Tests/RunicTests/OpenAIDashboardFetcherCreditsWaitTests.swift +0 -75
  468. package/Tests/RunicTests/OpenAIDashboardOffscreenHostTests.swift +0 -27
  469. package/Tests/RunicTests/OpenAIDashboardParserTests.swift +0 -134
  470. package/Tests/RunicTests/OpenAIWebAccountSwitchTests.swift +0 -53
  471. package/Tests/RunicTests/OpenRouterTokenStoreTestSupport.swift +0 -92
  472. package/Tests/RunicTests/PathBuilderTests.swift +0 -237
  473. package/Tests/RunicTests/ProviderFetchPipelineTests.swift +0 -160
  474. package/Tests/RunicTests/ProviderIconResourcesTests.swift +0 -38
  475. package/Tests/RunicTests/ProviderMetadataStatusLinkTests.swift +0 -16
  476. package/Tests/RunicTests/ProviderRegistryTests.swift +0 -29
  477. package/Tests/RunicTests/ProviderSettingsDescriptorTests.swift +0 -202
  478. package/Tests/RunicTests/ProviderToggleStoreTests.swift +0 -51
  479. package/Tests/RunicTests/RunicTests.swift +0 -120
  480. package/Tests/RunicTests/SessionQuotaNotificationLogicTests.swift +0 -36
  481. package/Tests/RunicTests/SettingsStoreTests.swift +0 -161
  482. package/Tests/RunicTests/StatusItemAnimationTests.swift +0 -49
  483. package/Tests/RunicTests/StatusMenuTests.swift +0 -434
  484. package/Tests/RunicTests/StatusProbeTests.swift +0 -377
  485. package/Tests/RunicTests/SubprocessRunnerTests.swift +0 -20
  486. package/Tests/RunicTests/SubscriptionDetectionTests.swift +0 -65
  487. package/Tests/RunicTests/TTYCommandRunnerTests.swift +0 -148
  488. package/Tests/RunicTests/TTYIntegrationTests.swift +0 -41
  489. package/Tests/RunicTests/TeamShowbackExporterTests.swift +0 -159
  490. package/Tests/RunicTests/TextParsingTests.swift +0 -12
  491. package/Tests/RunicTests/UsageFormatterTests.swift +0 -112
  492. package/Tests/RunicTests/UsageLedgerAnomalyDetectionTests.swift +0 -172
  493. package/Tests/RunicTests/UsageLedgerForecastTests.swift +0 -213
  494. package/Tests/RunicTests/UsageLedgerInsightsAdvisorTests.swift +0 -83
  495. package/Tests/RunicTests/UsageLedgerProjectNameTests.swift +0 -170
  496. package/Tests/RunicTests/UsagePaceTests.swift +0 -77
  497. package/Tests/RunicTests/UsagePaceTextTests.swift +0 -109
  498. package/Tests/RunicTests/UsagePolicyEngineTests.swift +0 -91
  499. package/Tests/RunicTests/WidgetSnapshotTests.swift +0 -45
  500. package/Tests/RunicTests/ZaiProviderTests.swift +0 -61
  501. package/Tests/RunicTests/ZaiTokenStoreTestSupport.swift +0 -6
  502. package/TestsLinux/PlatformGatingTests.swift +0 -46
  503. package/appcast.xml +0 -144
  504. package/assets/logo-concept-stack.svg +0 -24
  505. package/assets/logo-minimal-bars.svg +0 -15
  506. package/assets/logo.svg +0 -20
  507. package/assets/logo2.svg +0 -43
  508. package/bin/docs-list +0 -5
  509. package/build-and-run.sh +0 -369
  510. package/docs/.nojekyll +0 -1
  511. package/docs/CNAME +0 -1
  512. package/docs/antigravity.md +0 -75
  513. package/docs/architecture.md +0 -32
  514. package/docs/claude.md +0 -93
  515. package/docs/cli-commands/integration_guide.md +0 -371
  516. package/docs/cli-commands/quick_reference.md +0 -362
  517. package/docs/cli-commands/readme.md +0 -361
  518. package/docs/cli.md +0 -156
  519. package/docs/cloudkit_sync_guide.md +0 -495
  520. package/docs/codebase_review.md +0 -288
  521. package/docs/codex-oauth.md +0 -635
  522. package/docs/codex.md +0 -104
  523. package/docs/codexbar.png +0 -0
  524. package/docs/copilot.md +0 -44
  525. package/docs/cursor.md +0 -46
  526. package/docs/design/designcomparisonchart.md +0 -510
  527. package/docs/design/implementationguide.md +0 -792
  528. package/docs/design/menubaricondesignconcepts.md +0 -796
  529. package/docs/design/mockups/hybridiconconcept.svg +0 -62
  530. package/docs/design/mockups/infinityiconconcept.svg +0 -41
  531. package/docs/design/mockups/infinityiconstates.svg +0 -129
  532. package/docs/design/mockups/wavelogorefined.svg +0 -48
  533. package/docs/design/quick_summary.md +0 -426
  534. package/docs/design/readme.md +0 -478
  535. package/docs/design/sizespecifications.md +0 -575
  536. package/docs/design-system.md +0 -836
  537. package/docs/factory.md +0 -103
  538. package/docs/gemini.md +0 -73
  539. package/docs/icon.md +0 -37
  540. package/docs/icon.png +0 -0
  541. package/docs/index.html +0 -175
  542. package/docs/keychain_fix.md +0 -274
  543. package/docs/minimax.md +0 -71
  544. package/docs/packaging.md +0 -25
  545. package/docs/progress-bar-improvements.md +0 -240
  546. package/docs/progress-bar-quick-reference.md +0 -283
  547. package/docs/progress-bar-technical-details.md +0 -432
  548. package/docs/progress-bar-visual-test.swift +0 -375
  549. package/docs/provider.md +0 -202
  550. package/docs/providers.md +0 -86
  551. package/docs/refactor/macros.md +0 -35
  552. package/docs/refresh-loop.md +0 -22
  553. package/docs/releasing-homebrew.md +0 -35
  554. package/docs/releasing.md +0 -121
  555. package/docs/research/concrete_todo_2026-02-22.md +0 -47
  556. package/docs/research/core-feature-research.md +0 -248
  557. package/docs/research/feature_uiux_roadmap_2026-02-22.md +0 -202
  558. package/docs/research/parity_matrix.md +0 -49
  559. package/docs/research/provider_expansion_candidates_2026-02-22.md +0 -80
  560. package/docs/research/provider_model_token_project_matrix_2026-02-23.md +0 -46
  561. package/docs/research/release_gate_checklist.md +0 -57
  562. package/docs/site.css +0 -505
  563. package/docs/sparkle.md +0 -28
  564. package/docs/status.md +0 -28
  565. package/docs/sync/implementation.md +0 -393
  566. package/docs/sync/readme.md +0 -317
  567. package/docs/sync_files_summary.md +0 -391
  568. package/docs/sync_quick_reference.md +0 -225
  569. package/docs/todo.md +0 -11
  570. package/docs/ui.md +0 -29
  571. package/docs/web-integration.md +0 -9
  572. package/docs/widgets.md +0 -85
  573. package/docs/workflows/error-handling-improvements.md +0 -434
  574. package/docs/workflows/folder_structure.md +0 -299
  575. package/docs/workflows/loading_states.md +0 -446
  576. package/docs/workflows/loading_states_examples.md +0 -565
  577. package/docs/workflows/loading_states_flow.md +0 -430
  578. package/docs/workflows/performance_optimizations.md +0 -457
  579. package/docs/workflows/phase1-cli-testing-report.md +0 -313
  580. package/docs/workflows/quick_reference.md +0 -228
  581. package/docs/workflows/readme.md +0 -59
  582. package/docs/workflows/recent_improvements.md +0 -275
  583. package/docs/workflows/sync_enablement_summary.md +0 -400
  584. package/docs/zai.md +0 -43
  585. package/runic.png +0 -0
  586. package/version.env +0 -2
@@ -1,775 +0,0 @@
1
- import Foundation
2
- import CloudKit
3
- import CryptoKit
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 struct 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: 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: recordID, zoneID: zoneID)
97
- )
98
-
99
- // Sync metadata
100
- record["version"] = version as CKRecordValue
101
- record["modifiedAt"] = modifiedAt as CKRecordValue
102
- record["lastModifiedDeviceID"] = lastModifiedDeviceID as? CKRecordValue
103
-
104
- // Team data
105
- record["teamID"] = teamID as CKRecordValue
106
- record["name"] = name as CKRecordValue
107
- record["ownerUserID"] = ownerUserID as CKRecordValue
108
- record["totalQuota"] = totalQuota as CKRecordValue
109
- record["createdAt"] = createdAt as CKRecordValue
110
- record["updatedAt"] = updatedAt as CKRecordValue
111
- record["isActive"] = (isActive ? 1 : 0) as CKRecordValue
112
-
113
- // Optional fields
114
- record["description"] = description as? CKRecordValue
115
- record["avatarURL"] = avatarURL as? CKRecordValue
116
-
117
- return record
118
- }
119
-
120
- public static func fromCKRecord(_ ckRecord: CKRecord) throws -> TeamRecord {
121
- guard let version = ckRecord["version"] as? Int,
122
- let modifiedAt = ckRecord["modifiedAt"] as? Date,
123
- let teamID = ckRecord["teamID"] as? String,
124
- let name = ckRecord["name"] as? String,
125
- let ownerUserID = ckRecord["ownerUserID"] as? String,
126
- let totalQuota = ckRecord["totalQuota"] as? Int64,
127
- let createdAt = ckRecord["createdAt"] as? Date,
128
- let updatedAt = ckRecord["updatedAt"] as? Date,
129
- let isActiveInt = ckRecord["isActive"] as? Int
130
- else {
131
- throw SyncError.invalidRecordFormat("Missing required fields in Team record")
132
- }
133
-
134
- return TeamRecord(
135
- recordID: ckRecord.recordID.recordName,
136
- version: version,
137
- modifiedAt: modifiedAt,
138
- lastModifiedDeviceID: ckRecord["lastModifiedDeviceID"] as? String,
139
- teamID: teamID,
140
- name: name,
141
- ownerUserID: ownerUserID,
142
- totalQuota: totalQuota,
143
- createdAt: createdAt,
144
- updatedAt: updatedAt,
145
- description: ckRecord["description"] as? String,
146
- avatarURL: ckRecord["avatarURL"] as? String,
147
- isActive: isActiveInt == 1
148
- )
149
- }
150
- }
151
-
152
- // MARK: - Team Membership Record
153
-
154
- /// Team membership record for CloudKit synchronization
155
- ///
156
- /// Represents a user's membership in a team with role and quota information.
157
- /// - Record Type: "TeamMembership"
158
- /// - Queryable by: teamID, userID
159
- /// - References: Team record (parent)
160
- /// - Zone: TeamCollaborationZone (custom zone)
161
- public struct TeamMembershipRecord: SyncableRecord {
162
- public let recordID: String
163
- public let recordType: String = CloudKitRecordType.teamMembership
164
- public let version: Int
165
- public let modifiedAt: Date
166
- public let lastModifiedDeviceID: String?
167
-
168
- // Membership data
169
- public let membershipID: String
170
- public let teamID: String
171
- public let userID: String
172
- public let role: TeamRole
173
- public let quotaLimit: Int64?
174
- public let joinedAt: Date
175
-
176
- // Optional metadata
177
- public let email: String?
178
- public let displayName: String?
179
- public let invitedBy: String?
180
- public let acceptedAt: Date?
181
- public let isActive: Bool
182
-
183
- // Reference to parent team
184
- public let teamRecordName: String
185
-
186
- public enum TeamRole: String, Codable, Sendable {
187
- case owner = "owner"
188
- case admin = "admin"
189
- case member = "member"
190
- case viewer = "viewer"
191
- }
192
-
193
- public init(
194
- recordID: String = UUID().uuidString,
195
- version: Int = 1,
196
- modifiedAt: Date = Date(),
197
- lastModifiedDeviceID: String? = nil,
198
- membershipID: String = UUID().uuidString,
199
- teamID: String,
200
- userID: String,
201
- role: TeamRole,
202
- quotaLimit: Int64? = nil,
203
- joinedAt: Date = Date(),
204
- email: String? = nil,
205
- displayName: String? = nil,
206
- invitedBy: String? = nil,
207
- acceptedAt: Date? = nil,
208
- isActive: Bool = true,
209
- teamRecordName: String
210
- ) {
211
- self.recordID = recordID
212
- self.version = version
213
- self.modifiedAt = modifiedAt
214
- self.lastModifiedDeviceID = lastModifiedDeviceID
215
- self.membershipID = membershipID
216
- self.teamID = teamID
217
- self.userID = userID
218
- self.role = role
219
- self.quotaLimit = quotaLimit
220
- self.joinedAt = joinedAt
221
- self.email = email
222
- self.displayName = displayName
223
- self.invitedBy = invitedBy
224
- self.acceptedAt = acceptedAt
225
- self.isActive = isActive
226
- self.teamRecordName = teamRecordName
227
- }
228
-
229
- public func toCKRecord() throws -> CKRecord {
230
- let zoneID = TeamSyncZone.zoneID
231
- let record = CKRecord(
232
- recordType: recordType,
233
- recordID: CKRecord.ID(recordName: recordID, zoneID: zoneID)
234
- )
235
-
236
- // Sync metadata
237
- record["version"] = version as CKRecordValue
238
- record["modifiedAt"] = modifiedAt as CKRecordValue
239
- record["lastModifiedDeviceID"] = lastModifiedDeviceID as? CKRecordValue
240
-
241
- // Membership data
242
- record["membershipID"] = membershipID as CKRecordValue
243
- record["teamID"] = teamID as CKRecordValue
244
- record["userID"] = userID as CKRecordValue
245
- record["role"] = role.rawValue as CKRecordValue
246
- record["quotaLimit"] = quotaLimit as? CKRecordValue
247
- record["joinedAt"] = joinedAt as CKRecordValue
248
- record["isActive"] = (isActive ? 1 : 0) as CKRecordValue
249
-
250
- // Optional encrypted fields
251
- if let email = email {
252
- let encrypted = try encryptString(email)
253
- record["email"] = encrypted as CKRecordValue
254
- }
255
- record["displayName"] = displayName as? CKRecordValue
256
- record["invitedBy"] = invitedBy as? CKRecordValue
257
- record["acceptedAt"] = acceptedAt as? CKRecordValue
258
-
259
- // Reference to parent team
260
- let teamReference = CKRecord.Reference(
261
- recordID: CKRecord.ID(recordName: teamRecordName, zoneID: zoneID),
262
- action: .deleteSelf
263
- )
264
- record["teamReference"] = teamReference as CKRecordValue
265
-
266
- return record
267
- }
268
-
269
- public static func fromCKRecord(_ ckRecord: CKRecord) throws -> TeamMembershipRecord {
270
- guard let version = ckRecord["version"] as? Int,
271
- let modifiedAt = ckRecord["modifiedAt"] as? Date,
272
- let membershipID = ckRecord["membershipID"] as? String,
273
- let teamID = ckRecord["teamID"] as? String,
274
- let userID = ckRecord["userID"] as? String,
275
- let roleString = ckRecord["role"] as? String,
276
- let role = TeamRole(rawValue: roleString),
277
- let joinedAt = ckRecord["joinedAt"] as? Date,
278
- let isActiveInt = ckRecord["isActive"] as? Int,
279
- let teamReference = ckRecord["teamReference"] as? CKRecord.Reference
280
- else {
281
- throw SyncError.invalidRecordFormat("Missing required fields in TeamMembership record")
282
- }
283
-
284
- var email: String?
285
- if let encryptedEmail = ckRecord["email"] as? String {
286
- email = try? decryptString(encryptedEmail)
287
- }
288
-
289
- return TeamMembershipRecord(
290
- recordID: ckRecord.recordID.recordName,
291
- version: version,
292
- modifiedAt: modifiedAt,
293
- lastModifiedDeviceID: ckRecord["lastModifiedDeviceID"] as? String,
294
- membershipID: membershipID,
295
- teamID: teamID,
296
- userID: userID,
297
- role: role,
298
- quotaLimit: ckRecord["quotaLimit"] as? Int64,
299
- joinedAt: joinedAt,
300
- email: email,
301
- displayName: ckRecord["displayName"] as? String,
302
- invitedBy: ckRecord["invitedBy"] as? String,
303
- acceptedAt: ckRecord["acceptedAt"] as? Date,
304
- isActive: isActiveInt == 1,
305
- teamRecordName: teamReference.recordID.recordName
306
- )
307
- }
308
- }
309
-
310
- // MARK: - Project Ownership Record
311
-
312
- /// Project ownership record for CloudKit synchronization
313
- ///
314
- /// Represents ownership and sharing permissions for a project.
315
- /// - Record Type: "ProjectOwnership"
316
- /// - Queryable by: ownerUserID, teamID, projectID
317
- /// - References: Team record (optional - if team-owned)
318
- /// - Zone: TeamCollaborationZone (custom zone)
319
- public struct ProjectOwnershipRecord: SyncableRecord {
320
- public let recordID: String
321
- public let recordType: String = CloudKitRecordType.projectOwnership
322
- public let version: Int
323
- public let modifiedAt: Date
324
- public let lastModifiedDeviceID: String?
325
-
326
- // Project ownership data
327
- public let projectID: String
328
- public let teamID: String?
329
- public let ownerUserID: String
330
- public let sharedWith: [String]
331
- public let accessLevel: AccessLevel
332
- public let createdAt: Date
333
-
334
- // Optional metadata
335
- public let projectName: String?
336
- public let projectDescription: String?
337
- public let tags: [String]
338
- public let isArchived: Bool
339
-
340
- // Reference to team (if team-owned)
341
- public let teamRecordName: String?
342
-
343
- public enum AccessLevel: String, Codable, Sendable {
344
- case `private` = "private"
345
- case teamReadOnly = "team_read_only"
346
- case teamReadWrite = "team_read_write"
347
- case `public` = "public"
348
- }
349
-
350
- public init(
351
- recordID: String = UUID().uuidString,
352
- version: Int = 1,
353
- modifiedAt: Date = Date(),
354
- lastModifiedDeviceID: String? = nil,
355
- projectID: String = UUID().uuidString,
356
- teamID: String? = nil,
357
- ownerUserID: String,
358
- sharedWith: [String] = [],
359
- accessLevel: AccessLevel = .private,
360
- createdAt: Date = Date(),
361
- projectName: String? = nil,
362
- projectDescription: String? = nil,
363
- tags: [String] = [],
364
- isArchived: Bool = false,
365
- teamRecordName: String? = nil
366
- ) {
367
- self.recordID = recordID
368
- self.version = version
369
- self.modifiedAt = modifiedAt
370
- self.lastModifiedDeviceID = lastModifiedDeviceID
371
- self.projectID = projectID
372
- self.teamID = teamID
373
- self.ownerUserID = ownerUserID
374
- self.sharedWith = sharedWith
375
- self.accessLevel = accessLevel
376
- self.createdAt = createdAt
377
- self.projectName = projectName
378
- self.projectDescription = projectDescription
379
- self.tags = tags
380
- self.isArchived = isArchived
381
- self.teamRecordName = teamRecordName
382
- }
383
-
384
- public func toCKRecord() throws -> CKRecord {
385
- let zoneID = TeamSyncZone.zoneID
386
- let record = CKRecord(
387
- recordType: recordType,
388
- recordID: CKRecord.ID(recordName: recordID, zoneID: zoneID)
389
- )
390
-
391
- // Sync metadata
392
- record["version"] = version as CKRecordValue
393
- record["modifiedAt"] = modifiedAt as CKRecordValue
394
- record["lastModifiedDeviceID"] = lastModifiedDeviceID as? CKRecordValue
395
-
396
- // Project ownership data
397
- record["projectID"] = projectID as CKRecordValue
398
- record["teamID"] = teamID as? CKRecordValue
399
- record["ownerUserID"] = ownerUserID as CKRecordValue
400
- record["sharedWith"] = sharedWith as CKRecordValue
401
- record["accessLevel"] = accessLevel.rawValue as CKRecordValue
402
- record["createdAt"] = createdAt as CKRecordValue
403
- record["isArchived"] = (isArchived ? 1 : 0) as CKRecordValue
404
-
405
- // Optional metadata
406
- record["projectName"] = projectName as? CKRecordValue
407
- record["projectDescription"] = projectDescription as? CKRecordValue
408
- record["tags"] = tags as CKRecordValue
409
-
410
- // Reference to team (if team-owned)
411
- if let teamRecordName = teamRecordName {
412
- let teamReference = CKRecord.Reference(
413
- recordID: CKRecord.ID(recordName: teamRecordName, zoneID: zoneID),
414
- action: .none
415
- )
416
- record["teamReference"] = teamReference as CKRecordValue
417
- }
418
-
419
- return record
420
- }
421
-
422
- public static func fromCKRecord(_ ckRecord: CKRecord) throws -> ProjectOwnershipRecord {
423
- guard let version = ckRecord["version"] as? Int,
424
- let modifiedAt = ckRecord["modifiedAt"] as? Date,
425
- let projectID = ckRecord["projectID"] as? String,
426
- let ownerUserID = ckRecord["ownerUserID"] as? String,
427
- let sharedWith = ckRecord["sharedWith"] as? [String],
428
- let accessLevelString = ckRecord["accessLevel"] as? String,
429
- let accessLevel = AccessLevel(rawValue: accessLevelString),
430
- let createdAt = ckRecord["createdAt"] as? Date,
431
- let isArchivedInt = ckRecord["isArchived"] as? Int
432
- else {
433
- throw SyncError.invalidRecordFormat("Missing required fields in ProjectOwnership record")
434
- }
435
-
436
- let teamReference = ckRecord["teamReference"] as? CKRecord.Reference
437
-
438
- return ProjectOwnershipRecord(
439
- recordID: ckRecord.recordID.recordName,
440
- version: version,
441
- modifiedAt: modifiedAt,
442
- lastModifiedDeviceID: ckRecord["lastModifiedDeviceID"] as? String,
443
- projectID: projectID,
444
- teamID: ckRecord["teamID"] as? String,
445
- ownerUserID: ownerUserID,
446
- sharedWith: sharedWith,
447
- accessLevel: accessLevel,
448
- createdAt: createdAt,
449
- projectName: ckRecord["projectName"] as? String,
450
- projectDescription: ckRecord["projectDescription"] as? String,
451
- tags: ckRecord["tags"] as? [String] ?? [],
452
- isArchived: isArchivedInt == 1,
453
- teamRecordName: teamReference?.recordID.recordName
454
- )
455
- }
456
- }
457
-
458
- // MARK: - Team Usage Snapshot Record
459
-
460
- /// Team usage snapshot record for CloudKit synchronization
461
- ///
462
- /// Aggregates usage data across team members for tracking and quota management.
463
- /// - Record Type: "TeamUsageSnapshot"
464
- /// - Queryable by: teamID, date
465
- /// - References: Team record (parent)
466
- /// - Zone: TeamCollaborationZone (custom zone)
467
- public struct TeamUsageSnapshotRecord: SyncableRecord {
468
- public let recordID: String
469
- public let recordType: String = CloudKitRecordType.teamUsageSnapshot
470
- public let version: Int
471
- public let modifiedAt: Date
472
- public let lastModifiedDeviceID: String?
473
-
474
- // Team usage data
475
- public let teamID: String
476
- public let date: Date
477
- public let totalTokens: Int64
478
- public let totalCost: Double
479
- public let memberUsage: [String: MemberUsageData]
480
- public let quotaUsedPercent: Double
481
-
482
- // Additional metrics
483
- public let primaryProvider: String?
484
- public let mostActiveUser: String?
485
- public let averageTokensPerMember: Double
486
-
487
- // Reference to parent team
488
- public let teamRecordName: String
489
-
490
- public struct MemberUsageData: Codable, Sendable, Hashable {
491
- public let userID: String
492
- public let tokens: Int64
493
- public let cost: Double
494
- public let requestCount: Int
495
-
496
- public init(userID: String, tokens: Int64, cost: Double, requestCount: Int) {
497
- self.userID = userID
498
- self.tokens = tokens
499
- self.cost = cost
500
- self.requestCount = requestCount
501
- }
502
- }
503
-
504
- public init(
505
- recordID: String = UUID().uuidString,
506
- version: Int = 1,
507
- modifiedAt: Date = Date(),
508
- lastModifiedDeviceID: String? = nil,
509
- teamID: String,
510
- date: Date = Date(),
511
- totalTokens: Int64,
512
- totalCost: Double,
513
- memberUsage: [String: MemberUsageData] = [:],
514
- quotaUsedPercent: Double,
515
- primaryProvider: String? = nil,
516
- mostActiveUser: String? = nil,
517
- averageTokensPerMember: Double = 0.0,
518
- teamRecordName: String
519
- ) {
520
- self.recordID = recordID
521
- self.version = version
522
- self.modifiedAt = modifiedAt
523
- self.lastModifiedDeviceID = lastModifiedDeviceID
524
- self.teamID = teamID
525
- self.date = date
526
- self.totalTokens = totalTokens
527
- self.totalCost = totalCost
528
- self.memberUsage = memberUsage
529
- self.quotaUsedPercent = quotaUsedPercent
530
- self.primaryProvider = primaryProvider
531
- self.mostActiveUser = mostActiveUser
532
- self.averageTokensPerMember = averageTokensPerMember
533
- self.teamRecordName = teamRecordName
534
- }
535
-
536
- public func toCKRecord() throws -> CKRecord {
537
- let zoneID = TeamSyncZone.zoneID
538
- let record = CKRecord(
539
- recordType: recordType,
540
- recordID: CKRecord.ID(recordName: recordID, zoneID: zoneID)
541
- )
542
-
543
- // Sync metadata
544
- record["version"] = version as CKRecordValue
545
- record["modifiedAt"] = modifiedAt as CKRecordValue
546
- record["lastModifiedDeviceID"] = lastModifiedDeviceID as? CKRecordValue
547
-
548
- // Team usage data
549
- record["teamID"] = teamID as CKRecordValue
550
- record["date"] = date as CKRecordValue
551
- record["totalTokens"] = totalTokens as CKRecordValue
552
- record["totalCost"] = totalCost as CKRecordValue
553
- record["quotaUsedPercent"] = quotaUsedPercent as CKRecordValue
554
-
555
- // Encode member usage as JSON
556
- let encoder = JSONEncoder()
557
- let memberUsageData = try encoder.encode(memberUsage)
558
- record["memberUsage"] = String(data: memberUsageData, encoding: .utf8) as? CKRecordValue
559
-
560
- // Optional metrics
561
- record["primaryProvider"] = primaryProvider as? CKRecordValue
562
- record["mostActiveUser"] = mostActiveUser as? CKRecordValue
563
- record["averageTokensPerMember"] = averageTokensPerMember as CKRecordValue
564
-
565
- // Reference to parent team
566
- let teamReference = CKRecord.Reference(
567
- recordID: CKRecord.ID(recordName: teamRecordName, zoneID: zoneID),
568
- action: .deleteSelf
569
- )
570
- record["teamReference"] = teamReference as CKRecordValue
571
-
572
- return record
573
- }
574
-
575
- public static func fromCKRecord(_ ckRecord: CKRecord) throws -> TeamUsageSnapshotRecord {
576
- guard let version = ckRecord["version"] as? Int,
577
- let modifiedAt = ckRecord["modifiedAt"] as? Date,
578
- let teamID = ckRecord["teamID"] as? String,
579
- let date = ckRecord["date"] as? Date,
580
- let totalTokens = ckRecord["totalTokens"] as? Int64,
581
- let totalCost = ckRecord["totalCost"] as? Double,
582
- let quotaUsedPercent = ckRecord["quotaUsedPercent"] as? Double,
583
- let teamReference = ckRecord["teamReference"] as? CKRecord.Reference
584
- else {
585
- throw SyncError.invalidRecordFormat("Missing required fields in TeamUsageSnapshot record")
586
- }
587
-
588
- // Decode member usage from JSON
589
- var memberUsage: [String: MemberUsageData] = [:]
590
- if let memberUsageJSON = ckRecord["memberUsage"] as? String,
591
- let data = memberUsageJSON.data(using: .utf8) {
592
- let decoder = JSONDecoder()
593
- memberUsage = (try? decoder.decode([String: MemberUsageData].self, from: data)) ?? [:]
594
- }
595
-
596
- return TeamUsageSnapshotRecord(
597
- recordID: ckRecord.recordID.recordName,
598
- version: version,
599
- modifiedAt: modifiedAt,
600
- lastModifiedDeviceID: ckRecord["lastModifiedDeviceID"] as? String,
601
- teamID: teamID,
602
- date: date,
603
- totalTokens: totalTokens,
604
- totalCost: totalCost,
605
- memberUsage: memberUsage,
606
- quotaUsedPercent: quotaUsedPercent,
607
- primaryProvider: ckRecord["primaryProvider"] as? String,
608
- mostActiveUser: ckRecord["mostActiveUser"] as? String,
609
- averageTokensPerMember: ckRecord["averageTokensPerMember"] as? Double ?? 0.0,
610
- teamRecordName: teamReference.recordID.recordName
611
- )
612
- }
613
- }
614
-
615
- // MARK: - CloudKit Query Helpers
616
-
617
- /// Helper methods for querying team-related records
618
- public enum TeamRecordQuery {
619
-
620
- /// Creates a predicate to query teams by owner
621
- public static func teamsByOwner(_ ownerUserID: String) -> NSPredicate {
622
- NSPredicate(format: "ownerUserID == %@", ownerUserID)
623
- }
624
-
625
- /// Creates a predicate to query memberships by team
626
- public static func membershipsByTeam(_ teamID: String) -> NSPredicate {
627
- NSPredicate(format: "teamID == %@ AND isActive == 1", teamID)
628
- }
629
-
630
- /// Creates a predicate to query memberships by user
631
- public static func membershipsByUser(_ userID: String) -> NSPredicate {
632
- NSPredicate(format: "userID == %@ AND isActive == 1", userID)
633
- }
634
-
635
- /// Creates a predicate to query projects by owner
636
- public static func projectsByOwner(_ ownerUserID: String) -> NSPredicate {
637
- NSPredicate(format: "ownerUserID == %@ AND isArchived == 0", ownerUserID)
638
- }
639
-
640
- /// Creates a predicate to query projects by team
641
- public static func projectsByTeam(_ teamID: String) -> NSPredicate {
642
- NSPredicate(format: "teamID == %@ AND isArchived == 0", teamID)
643
- }
644
-
645
- /// Creates a predicate to query team usage snapshots by date range
646
- public static func teamUsageByDateRange(teamID: String, startDate: Date, endDate: Date) -> NSPredicate {
647
- NSPredicate(format: "teamID == %@ AND date >= %@ AND date <= %@", teamID, startDate as NSDate, endDate as NSDate)
648
- }
649
-
650
- /// Creates a predicate to query latest team usage
651
- public static func latestTeamUsage(_ teamID: String) -> NSPredicate {
652
- NSPredicate(format: "teamID == %@", teamID)
653
- }
654
- }
655
-
656
- // MARK: - CloudKit Index Configuration
657
-
658
- /// Recommended CloudKit indexes for efficient querying
659
- ///
660
- /// Configure these indexes in CloudKit Dashboard for optimal performance:
661
- ///
662
- /// Team Record:
663
- /// - ownerUserID (Queryable, Sortable)
664
- /// - isActive (Queryable)
665
- /// - createdAt (Sortable)
666
- ///
667
- /// TeamMembership Record:
668
- /// - teamID (Queryable, Sortable)
669
- /// - userID (Queryable, Sortable)
670
- /// - isActive (Queryable)
671
- /// - role (Queryable)
672
- /// - joinedAt (Sortable)
673
- ///
674
- /// ProjectOwnership Record:
675
- /// - ownerUserID (Queryable, Sortable)
676
- /// - teamID (Queryable, Sortable)
677
- /// - projectID (Queryable)
678
- /// - isArchived (Queryable)
679
- /// - accessLevel (Queryable)
680
- /// - createdAt (Sortable)
681
- ///
682
- /// TeamUsageSnapshot Record:
683
- /// - teamID (Queryable, Sortable)
684
- /// - date (Queryable, Sortable)
685
- /// - quotaUsedPercent (Sortable)
686
- public enum TeamRecordIndexes {
687
- // This is a documentation enum - configure actual indexes in CloudKit Dashboard
688
- }
689
-
690
- // MARK: - Encryption Helpers (Team-specific)
691
-
692
- /// Encrypts a string using AES-GCM encryption (team-specific wrapper)
693
- private func encryptString(_ plaintext: String) throws -> String {
694
- guard let data = plaintext.data(using: .utf8) else {
695
- throw SyncError.encryptionFailed("Failed to convert string to data")
696
- }
697
-
698
- let key = getOrCreateEncryptionKey()
699
- let sealed = try AES.GCM.seal(data, using: key)
700
-
701
- guard let combined = sealed.combined else {
702
- throw SyncError.encryptionFailed("Failed to create sealed box")
703
- }
704
-
705
- return combined.base64EncodedString()
706
- }
707
-
708
- /// Decrypts a string that was encrypted with encryptString
709
- private func decryptString(_ encrypted: String) throws -> String {
710
- guard let combined = Data(base64Encoded: encrypted) else {
711
- throw SyncError.encryptionFailed("Failed to decode base64")
712
- }
713
-
714
- let key = getOrCreateEncryptionKey()
715
- let sealedBox = try AES.GCM.SealedBox(combined: combined)
716
- let decrypted = try AES.GCM.open(sealedBox, using: key)
717
-
718
- guard let plaintext = String(data: decrypted, encoding: .utf8) else {
719
- throw SyncError.encryptionFailed("Failed to convert decrypted data to string")
720
- }
721
-
722
- return plaintext
723
- }
724
-
725
- /// Retrieves or creates an encryption key for sensitive data
726
- private func getOrCreateEncryptionKey() -> SymmetricKey {
727
- let keychainKey = "com.runic.sync.team.encryption.key"
728
-
729
- // Try to load existing key from Keychain
730
- if let keyData = loadFromKeychain(key: keychainKey) {
731
- return SymmetricKey(data: keyData)
732
- }
733
-
734
- // Generate new key
735
- let key = SymmetricKey(size: .bits256)
736
- let keyData = key.withUnsafeBytes { Data($0) }
737
-
738
- // Store in Keychain
739
- saveToKeychain(key: keychainKey, data: keyData)
740
-
741
- return key
742
- }
743
-
744
- private func saveToKeychain(key: String, data: Data) {
745
- let query: [String: Any] = [
746
- kSecClass as String: kSecClassGenericPassword,
747
- kSecAttrService as String: "com.sriinnu.athena.Runic",
748
- kSecAttrAccount as String: key,
749
- kSecUseDataProtectionKeychain as String: true,
750
- kSecValueData as String: data,
751
- kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock
752
- ]
753
- SecItemDelete(query as CFDictionary)
754
- SecItemAdd(query as CFDictionary, nil)
755
- }
756
-
757
- private func loadFromKeychain(key: String) -> Data? {
758
- var query: [String: Any] = [
759
- kSecClass as String: kSecClassGenericPassword,
760
- kSecAttrService as String: "com.sriinnu.athena.Runic",
761
- kSecAttrAccount as String: key,
762
- kSecUseDataProtectionKeychain as String: true,
763
- kSecUseAuthenticationUI as String: "kSecUseAuthenticationUIFail" as CFString,
764
- kSecReturnData as String: true
765
- ]
766
- let authContext = LAContext()
767
- authContext.interactionNotAllowed = true
768
- query[kSecUseAuthenticationContext as String] = authContext
769
- var result: AnyObject?
770
- let status = SecItemCopyMatching(query as CFDictionary, &result)
771
- if status == errSecInteractionNotAllowed {
772
- return nil
773
- }
774
- return status == errSecSuccess ? result as? Data : nil
775
- }