@sriinnu/runic 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.swiftformat +50 -0
- package/.swiftlint.yml +160 -0
- package/CHANGELOG.md +307 -0
- package/CONTRIBUTING.md +456 -0
- package/Icon.icns +0 -0
- package/Icon.icon/Assets/runic.png +0 -0
- package/Icon.icon/icon.json +36 -0
- package/LICENSE +21 -0
- package/Package.resolved +51 -0
- package/Package.swift +136 -0
- package/Packages/Helix/LICENSE +21 -0
- package/Packages/Helix/Package.swift +29 -0
- package/Packages/Helix/README.md +976 -0
- package/Packages/Helix/Sources/Helix/Binding.swift +111 -0
- package/Packages/Helix/Sources/Helix/CommandParser.swift +160 -0
- package/Packages/Helix/Sources/Helix/CommandSignature.swift +117 -0
- package/Packages/Helix/Sources/Helix/ExpressibleFromArgument.swift +72 -0
- package/Packages/Helix/Sources/Helix/HelpGenerator.swift +175 -0
- package/Packages/Helix/Sources/Helix/NameSpecification.swift +98 -0
- package/Packages/Helix/Sources/Helix/ParsableCommand.swift +204 -0
- package/Packages/Helix/Sources/Helix/Platform/DarwinPlatformContext.swift +44 -0
- package/Packages/Helix/Sources/Helix/Platform/LinuxPlatformContext.swift +34 -0
- package/Packages/Helix/Sources/Helix/Platform/PlatformContext+Default.swift +91 -0
- package/Packages/Helix/Sources/Helix/Platform/PlatformContext.swift +94 -0
- package/Packages/Helix/Sources/Helix/Platform/PlatformPath.swift +167 -0
- package/Packages/Helix/Sources/Helix/Platform/Stdio.swift +99 -0
- package/Packages/Helix/Sources/Helix/Platform/WebPlatformContext.swift +146 -0
- package/Packages/Helix/Sources/Helix/Platform/WindowsPlatformContext.swift +97 -0
- package/Packages/Helix/Sources/Helix/Program.swift +204 -0
- package/Packages/Helix/Sources/Helix/PropertyWrappers.swift +367 -0
- package/Packages/Silo/LICENSE +21 -0
- package/Packages/Silo/Package.swift +34 -0
- package/Packages/Silo/README.md +466 -0
- package/Packages/Silo/Sources/Silo/BinaryCookiesReader.swift +169 -0
- package/Packages/Silo/Sources/Silo/BrowserCookieAnalytics.swift +365 -0
- package/Packages/Silo/Sources/Silo/BrowserCookieBackends.swift +594 -0
- package/Packages/Silo/Sources/Silo/BrowserCookieClient.swift +326 -0
- package/Packages/Silo/Sources/Silo/BrowserCookieExport.swift +154 -0
- package/Packages/Silo/Sources/Silo/BrowserCookieImport.swift +119 -0
- package/Packages/Silo/Sources/Silo/BrowserCookieMockStore.swift +121 -0
- package/Packages/Silo/Sources/Silo/BrowserCookieModels.swift +391 -0
- package/Packages/Silo/Sources/Silo/ChromiumCookieReader.swift +240 -0
- package/Packages/Silo/Sources/Silo/CryptoSupport.swift +86 -0
- package/Packages/Silo/Sources/Silo/FirefoxCookieReader.swift +172 -0
- package/Packages/Silo/Sources/Silo/LinuxChromiumCookieReader.swift +172 -0
- package/Packages/Silo/Sources/Silo/LinuxSecretService.swift +105 -0
- package/Packages/Silo/Sources/Silo/MacOSChromiumCookieReader.swift +191 -0
- package/Packages/Silo/Sources/Silo/SQLiteSnapshot.swift +41 -0
- package/Packages/Silo/Sources/Silo/WindowsChromiumCookieReader.swift +110 -0
- package/README.md +109 -0
- package/RuniciOS/App/RuniciOSApp.swift +105 -0
- package/RuniciOS/Core/iOSUsageStore.swift +192 -0
- package/RuniciOS/Views/ProviderDetailView.swift +312 -0
- package/RuniciOS/Views/ProviderListView.swift +228 -0
- package/RuniciOS/Widgets/LargeWidget.swift +367 -0
- package/RuniciOS/Widgets/LiveActivity.swift +342 -0
- package/RuniciOS/Widgets/LockScreenWidget.swift +273 -0
- package/RuniciOS/Widgets/MediumWidget.swift +370 -0
- package/RuniciOS/Widgets/RunicWidget.swift +274 -0
- package/RuniciOS/Widgets/SmallWidget.swift +281 -0
- package/RuniciOS/Widgets/WidgetModels.swift +285 -0
- package/RuniciOS/Widgets/WidgetTimeline.swift +270 -0
- package/Scripts/CREATION-SUMMARY.md +367 -0
- package/Scripts/DIRECTORY-STRUCTURE.md +358 -0
- package/Scripts/GETTING-STARTED-CHECKLIST.md +364 -0
- package/Scripts/INDEX.md +365 -0
- package/Scripts/QUICK-REFERENCE.md +164 -0
- package/Scripts/README-SCRIPTS.md +926 -0
- package/Scripts/build-android.sh +526 -0
- package/Scripts/build-ios.sh +529 -0
- package/Scripts/build-macos.sh +603 -0
- package/Scripts/build-windows.sh +504 -0
- package/Scripts/build_icon.sh +49 -0
- package/Scripts/changelog-to-html.sh +89 -0
- package/Scripts/check-release-assets.sh +10 -0
- package/Scripts/ci-config.yml +474 -0
- package/Scripts/compile_and_run.sh +219 -0
- package/Scripts/compile_and_run_adhoc.sh +4 -0
- package/Scripts/docs-list.mjs +119 -0
- package/Scripts/make_appcast.sh +58 -0
- package/Scripts/package_app.sh +409 -0
- package/Scripts/release-lib.sh +214 -0
- package/Scripts/release.sh +76 -0
- package/Scripts/setup-all.sh +387 -0
- package/Scripts/setup-ios.sh +404 -0
- package/Scripts/setup-react-native.sh +523 -0
- package/Scripts/sign-and-notarize.sh +122 -0
- package/Scripts/test_live_update.sh +38 -0
- package/Scripts/validate_changelog.sh +23 -0
- package/Scripts/verify_appcast.sh +92 -0
- package/Sources/Runic/About.swift +93 -0
- package/Sources/Runic/AppNotifications.swift +115 -0
- package/Sources/Runic/Controllers/StatusItemController+Actions.swift +657 -0
- package/Sources/Runic/Controllers/StatusItemController+Animation.swift +518 -0
- package/Sources/Runic/Controllers/StatusItemController+ChartSubmenus.swift +810 -0
- package/Sources/Runic/Controllers/StatusItemController+CustomProviders.swift +87 -0
- package/Sources/Runic/Controllers/StatusItemController+Menu.swift +1379 -0
- package/Sources/Runic/Controllers/StatusItemController+MenuCards.swift +337 -0
- package/Sources/Runic/Controllers/StatusItemController+MenuHelpers.swift +395 -0
- package/Sources/Runic/Controllers/StatusItemController.swift +360 -0
- package/Sources/Runic/Core/BudgetNotificationManager.swift +80 -0
- package/Sources/Runic/Core/Login/ClaudeLoginRunner.swift +103 -0
- package/Sources/Runic/Core/Login/CodexLoginRunner.swift +154 -0
- package/Sources/Runic/Core/Login/CursorLoginRunner.swift +206 -0
- package/Sources/Runic/Core/Login/GeminiLoginRunner.swift +95 -0
- package/Sources/Runic/Core/Rendering/IconRenderer.swift +1216 -0
- package/Sources/Runic/Core/Rendering/IconView.swift +120 -0
- package/Sources/Runic/Core/Rendering/ProviderBrandIcon.swift +71 -0
- package/Sources/Runic/Core/RunicAnimation.swift +53 -0
- package/Sources/Runic/Core/RunicColors.swift +73 -0
- package/Sources/Runic/Core/RunicCornerRadius.swift +15 -0
- package/Sources/Runic/Core/RunicSpacing.swift +68 -0
- package/Sources/Runic/Core/Stores/AuggieTokenStore.swift +143 -0
- package/Sources/Runic/Core/Stores/AzureOpenAITokenStore.swift +143 -0
- package/Sources/Runic/Core/Stores/CerebrasTokenStore.swift +143 -0
- package/Sources/Runic/Core/Stores/CohereTokenStore.swift +143 -0
- package/Sources/Runic/Core/Stores/CopilotTokenStore.swift +143 -0
- package/Sources/Runic/Core/Stores/CustomProviderStore.swift +158 -0
- package/Sources/Runic/Core/Stores/DeepSeekTokenStore.swift +143 -0
- package/Sources/Runic/Core/Stores/FireworksTokenStore.swift +143 -0
- package/Sources/Runic/Core/Stores/GroqTokenStore.swift +143 -0
- package/Sources/Runic/Core/Stores/KimiTokenStore.swift +143 -0
- package/Sources/Runic/Core/Stores/MiniMaxCookieHeaderStore.swift +143 -0
- package/Sources/Runic/Core/Stores/MiniMaxGroupIDStore.swift +143 -0
- package/Sources/Runic/Core/Stores/MiniMaxTokenStore.swift +143 -0
- package/Sources/Runic/Core/Stores/MistralTokenStore.swift +143 -0
- package/Sources/Runic/Core/Stores/OpenRouterTokenStore.swift +143 -0
- package/Sources/Runic/Core/Stores/PerplexityTokenStore.swift +143 -0
- package/Sources/Runic/Core/Stores/ProviderToggleStore.swift +30 -0
- package/Sources/Runic/Core/Stores/QwenTokenStore.swift +143 -0
- package/Sources/Runic/Core/Stores/SambaNovaTokenStore.swift +143 -0
- package/Sources/Runic/Core/Stores/SettingsStore.swift +1702 -0
- package/Sources/Runic/Core/Stores/TogetherTokenStore.swift +143 -0
- package/Sources/Runic/Core/Stores/UsageStore+Accessors.swift +20 -0
- package/Sources/Runic/Core/Stores/UsageStore+Status.swift +189 -0
- package/Sources/Runic/Core/Stores/UsageStore+TokenCost.swift +33 -0
- package/Sources/Runic/Core/Stores/UsageStore+WidgetSnapshot.swift +67 -0
- package/Sources/Runic/Core/Stores/UsageStore.swift +3564 -0
- package/Sources/Runic/Core/Stores/XAITokenStore.swift +143 -0
- package/Sources/Runic/Core/Stores/ZaiTokenStore.swift +143 -0
- package/Sources/Runic/Core/UsageExporter.swift +193 -0
- package/Sources/Runic/Date+RelativeDescription.swift +21 -0
- package/Sources/Runic/HiddenWindowView.swift +32 -0
- package/Sources/Runic/InstallOrigin.swift +9 -0
- package/Sources/Runic/KeyboardShortcuts+Names.swift +6 -0
- package/Sources/Runic/MouseLocationReader.swift +65 -0
- package/Sources/Runic/Notifications+Runic.swift +6 -0
- package/Sources/Runic/OpenAICreditsPurchaseWindowController.swift +503 -0
- package/Sources/Runic/ProviderRegistry.swift +100 -0
- package/Sources/Runic/ProviderSwitcherButtons.swift +267 -0
- package/Sources/Runic/Providers/Antigravity/AntigravityLoginFlow.swift +11 -0
- package/Sources/Runic/Providers/Antigravity/AntigravityProviderImplementation.swift +14 -0
- package/Sources/Runic/Providers/Auggie/AuggieProviderImplementation.swift +24 -0
- package/Sources/Runic/Providers/Azure/AzureProviderImplementation.swift +52 -0
- package/Sources/Runic/Providers/Bedrock/BedrockProviderImplementation.swift +42 -0
- package/Sources/Runic/Providers/Cerebras/CerebrasProviderImplementation.swift +24 -0
- package/Sources/Runic/Providers/Claude/ClaudeLoginFlow.swift +26 -0
- package/Sources/Runic/Providers/Claude/ClaudeProviderImplementation.swift +14 -0
- package/Sources/Runic/Providers/Codex/CodexLoginFlow.swift +18 -0
- package/Sources/Runic/Providers/Codex/CodexProviderImplementation.swift +15 -0
- package/Sources/Runic/Providers/Cohere/CohereProviderImplementation.swift +24 -0
- package/Sources/Runic/Providers/Copilot/CopilotLoginFlow.swift +193 -0
- package/Sources/Runic/Providers/Copilot/CopilotProviderImplementation.swift +110 -0
- package/Sources/Runic/Providers/Cursor/CursorLoginFlow.swift +28 -0
- package/Sources/Runic/Providers/Cursor/CursorProviderImplementation.swift +15 -0
- package/Sources/Runic/Providers/DeepSeek/DeepSeekProviderImplementation.swift +24 -0
- package/Sources/Runic/Providers/Factory/FactoryLoginFlow.swift +12 -0
- package/Sources/Runic/Providers/Factory/FactoryProviderImplementation.swift +15 -0
- package/Sources/Runic/Providers/Fireworks/FireworksProviderImplementation.swift +24 -0
- package/Sources/Runic/Providers/Gemini/GeminiLoginFlow.swift +20 -0
- package/Sources/Runic/Providers/Gemini/GeminiProviderImplementation.swift +15 -0
- package/Sources/Runic/Providers/Groq/GroqProviderImplementation.swift +24 -0
- package/Sources/Runic/Providers/Kimi/KimiProviderImplementation.swift +24 -0
- package/Sources/Runic/Providers/MiniMax/MiniMaxProviderImplementation.swift +32 -0
- package/Sources/Runic/Providers/Mistral/MistralProviderImplementation.swift +24 -0
- package/Sources/Runic/Providers/OpenRouter/OpenRouterProviderImplementation.swift +24 -0
- package/Sources/Runic/Providers/Perplexity/PerplexityProviderImplementation.swift +24 -0
- package/Sources/Runic/Providers/SambaNova/SambaNovaProviderImplementation.swift +24 -0
- package/Sources/Runic/Providers/Shared/ProviderCatalog.swift +15 -0
- package/Sources/Runic/Providers/Shared/ProviderImplementation.swift +48 -0
- package/Sources/Runic/Providers/Shared/ProviderImplementationRegistry.swift +66 -0
- package/Sources/Runic/Providers/Shared/ProviderLoginFlow.swift +12 -0
- package/Sources/Runic/Providers/Shared/ProviderSettingsDescriptors.swift +99 -0
- package/Sources/Runic/Providers/Shared/SystemSettingsLinks.swift +18 -0
- package/Sources/Runic/Providers/Together/TogetherProviderImplementation.swift +24 -0
- package/Sources/Runic/Providers/XAI/XAIProviderImplementation.swift +24 -0
- package/Sources/Runic/Providers/Zai/ZaiProviderImplementation.swift +24 -0
- package/Sources/Runic/Resources/ProviderIcon-antigravity.svg +2 -0
- package/Sources/Runic/Resources/ProviderIcon-auggie.svg +3 -0
- package/Sources/Runic/Resources/ProviderIcon-azure.svg +5 -0
- package/Sources/Runic/Resources/ProviderIcon-bedrock.svg +7 -0
- package/Sources/Runic/Resources/ProviderIcon-cerebras.svg +3 -0
- package/Sources/Runic/Resources/ProviderIcon-claude.svg +1 -0
- package/Sources/Runic/Resources/ProviderIcon-codex.svg +1 -0
- package/Sources/Runic/Resources/ProviderIcon-cohere.svg +3 -0
- package/Sources/Runic/Resources/ProviderIcon-copilot.svg +1 -0
- package/Sources/Runic/Resources/ProviderIcon-cursor.svg +3 -0
- package/Sources/Runic/Resources/ProviderIcon-deepseek.svg +4 -0
- package/Sources/Runic/Resources/ProviderIcon-factory.svg +3 -0
- package/Sources/Runic/Resources/ProviderIcon-fireworks.svg +3 -0
- package/Sources/Runic/Resources/ProviderIcon-gemini.svg +1 -0
- package/Sources/Runic/Resources/ProviderIcon-groq.svg +1 -0
- package/Sources/Runic/Resources/ProviderIcon-kimi.svg +4 -0
- package/Sources/Runic/Resources/ProviderIcon-minimax.svg +1 -0
- package/Sources/Runic/Resources/ProviderIcon-mistral.svg +5 -0
- package/Sources/Runic/Resources/ProviderIcon-openrouter.svg +7 -0
- package/Sources/Runic/Resources/ProviderIcon-perplexity.svg +4 -0
- package/Sources/Runic/Resources/ProviderIcon-qwen.svg +9 -0
- package/Sources/Runic/Resources/ProviderIcon-sambanova.svg +4 -0
- package/Sources/Runic/Resources/ProviderIcon-together.svg +5 -0
- package/Sources/Runic/Resources/ProviderIcon-vertexai.svg +17 -0
- package/Sources/Runic/Resources/ProviderIcon-xai.svg +3 -0
- package/Sources/Runic/Resources/ProviderIcon-zai.svg +5 -0
- package/Sources/Runic/Resources/RunicMenubarIcon.svg +7 -0
- package/Sources/Runic/RunicApp.swift +357 -0
- package/Sources/Runic/SessionQuotaNotifications.swift +58 -0
- package/Sources/Runic/UsagePaceText.swift +52 -0
- package/Sources/Runic/UsageProgressBar.swift +224 -0
- package/Sources/Runic/Utilities/DisplayLink.swift +96 -0
- package/Sources/Runic/Utilities/LoadingPattern.swift +60 -0
- package/Sources/Runic/Utilities/PerformanceConstants.swift +85 -0
- package/Sources/Runic/Views/Menu/AlertsMenuView.swift +256 -0
- package/Sources/Runic/Views/Menu/ChartPanelStyle.swift +22 -0
- package/Sources/Runic/Views/Menu/CostComparativeChartMenuView.swift +275 -0
- package/Sources/Runic/Views/Menu/CostHistoryChartMenuView.swift +377 -0
- package/Sources/Runic/Views/Menu/CreditsHistoryChartMenuView.swift +312 -0
- package/Sources/Runic/Views/Menu/EfficiencyMetricsMenuView.swift +312 -0
- package/Sources/Runic/Views/Menu/HeroStatCardsMenuView.swift +228 -0
- package/Sources/Runic/Views/Menu/HourlyActivityChartMenuView.swift +228 -0
- package/Sources/Runic/Views/Menu/InlineUsageChartView.swift +162 -0
- package/Sources/Runic/Views/Menu/MenuCardEntranceModifier.swift +64 -0
- package/Sources/Runic/Views/Menu/MenuCardSidebarView.swift +268 -0
- package/Sources/Runic/Views/Menu/MenuCardSkeletonView.swift +104 -0
- package/Sources/Runic/Views/Menu/MenuCardView.swift +1900 -0
- package/Sources/Runic/Views/Menu/MenuContent.swift +150 -0
- package/Sources/Runic/Views/Menu/MenuDescriptor.swift +369 -0
- package/Sources/Runic/Views/Menu/MenuHighlightStyle.swift +42 -0
- package/Sources/Runic/Views/Menu/ModelBreakdownMenuView.swift +235 -0
- package/Sources/Runic/Views/Menu/OverviewMenuView.swift +141 -0
- package/Sources/Runic/Views/Menu/ProjectBreakdownMenuView.swift +209 -0
- package/Sources/Runic/Views/Menu/ProjectBudgetMenuView.swift +220 -0
- package/Sources/Runic/Views/Menu/ProviderTabBarView.swift +88 -0
- package/Sources/Runic/Views/Menu/SubscriptionUtilizationChartMenuView.swift +201 -0
- package/Sources/Runic/Views/Menu/UsageBreakdownChartMenuView.swift +398 -0
- package/Sources/Runic/Views/Menu/UsageHeatmapMenuView.swift +232 -0
- package/Sources/Runic/Views/Menu/UsageTimelineChartMenuView.swift +417 -0
- package/Sources/Runic/Views/Menu/UsageWindowComparisonChartMenuView.swift +190 -0
- package/Sources/Runic/Views/Menu/WeeklyActivityChartMenuView.swift +132 -0
- package/Sources/Runic/Views/Performance/PerformanceDashboardView.swift +618 -0
- package/Sources/Runic/Views/Preferences/LiquidComponents.swift +305 -0
- package/Sources/Runic/Views/Preferences/PreferencesAboutPane.swift +271 -0
- package/Sources/Runic/Views/Preferences/PreferencesAdvancedPane.swift +268 -0
- package/Sources/Runic/Views/Preferences/PreferencesAlertsPane.swift +422 -0
- package/Sources/Runic/Views/Preferences/PreferencesAnalyticsPane.swift +641 -0
- package/Sources/Runic/Views/Preferences/PreferencesBudgetsPane.swift +344 -0
- package/Sources/Runic/Views/Preferences/PreferencesComponents.swift +230 -0
- package/Sources/Runic/Views/Preferences/PreferencesCustomProvidersPane.swift +322 -0
- package/Sources/Runic/Views/Preferences/PreferencesDebugPane.swift +469 -0
- package/Sources/Runic/Views/Preferences/PreferencesGeneralPane.swift +231 -0
- package/Sources/Runic/Views/Preferences/PreferencesHelpPane.swift +50 -0
- package/Sources/Runic/Views/Preferences/PreferencesIntegrationsPane.swift +497 -0
- package/Sources/Runic/Views/Preferences/PreferencesPerformancePane.swift +288 -0
- package/Sources/Runic/Views/Preferences/PreferencesProvidersPane.swift +3435 -0
- package/Sources/Runic/Views/Preferences/PreferencesSelection.swift +25 -0
- package/Sources/Runic/Views/Preferences/PreferencesSyncPane.swift +59 -0
- package/Sources/Runic/Views/Preferences/PreferencesView.swift +206 -0
- package/Sources/Runic/Views/Rating/QualityRatingView.swift +238 -0
- package/Sources/Runic/Views/Team/TeamDashboardView.swift +371 -0
- package/Sources/Runic/Views/Team/TeamInviteSheet.swift +175 -0
- package/Sources/Runic/Views/Team/TeamManagementView.swift +761 -0
- package/Sources/Runic/Views/Team/TeamMemberRow.swift +181 -0
- package/Sources/RunicCLI/CLIEntry.swift +942 -0
- package/Sources/RunicCLI/CLIRenderer.swift +87 -0
- package/Sources/RunicCLI/Commands/EnhancedUsageCommand.swift +588 -0
- package/Sources/RunicCLI/Commands/ModelsCommand.swift +362 -0
- package/Sources/RunicCLI/Commands/ProjectsCommand.swift +439 -0
- package/Sources/RunicCLI/Commands/ResetCommand.swift +429 -0
- package/Sources/RunicCLI/Commands/UsageLedgerSourceFactory.swift +168 -0
- package/Sources/RunicClaudeWatchdog/main.swift +122 -0
- package/Sources/RunicClaudeWebProbe/main.swift +62 -0
- package/Sources/RunicCore/AlertRuleStore.swift +187 -0
- package/Sources/RunicCore/BrowserCookieImportOrder.swift +25 -0
- package/Sources/RunicCore/CopilotUsageModels.swift +84 -0
- package/Sources/RunicCore/CostUsageFetcher.swift +119 -0
- package/Sources/RunicCore/CostUsageModels.swift +479 -0
- package/Sources/RunicCore/CreditsModels.swift +50 -0
- package/Sources/RunicCore/CustomProviders/CustomProviderModels.swift +269 -0
- package/Sources/RunicCore/CustomProviders/GenericProviderFetcher.swift +622 -0
- package/Sources/RunicCore/CustomProviders/ProviderTemplates.swift +500 -0
- package/Sources/RunicCore/Host/PTY/TTYCommandRunner.swift +679 -0
- package/Sources/RunicCore/Host/Process/SubprocessRunner.swift +135 -0
- package/Sources/RunicCore/Integrations/GitHubIntegration.swift +173 -0
- package/Sources/RunicCore/Logging/JSONStderrLogHandler.swift +79 -0
- package/Sources/RunicCore/Logging/OSLogLogHandler.swift +86 -0
- package/Sources/RunicCore/Logging/RunicLog.swift +123 -0
- package/Sources/RunicCore/Models/EnhancedUsageModels.swift +371 -0
- package/Sources/RunicCore/OpenAIDashboardModels.swift +210 -0
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardBrowserCookieImporter.swift +676 -0
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardFetcher.swift +492 -0
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardNavigationDelegate.swift +51 -0
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardParser.swift +483 -0
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardScrapeScript.swift +558 -0
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardWebViewCache.swift +204 -0
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardWebsiteDataStore.swift +78 -0
- package/Sources/RunicCore/PathEnvironment.swift +482 -0
- package/Sources/RunicCore/Performance/PerformanceModels.swift +371 -0
- package/Sources/RunicCore/Performance/PerformanceStorageImpl.swift +409 -0
- package/Sources/RunicCore/Policy/UsagePolicyEngine.swift +178 -0
- package/Sources/RunicCore/ProjectBudgetStore.swift +99 -0
- package/Sources/RunicCore/ProviderCostSnapshot.swift +29 -0
- package/Sources/RunicCore/Providers/Antigravity/AntigravityProviderDescriptor.swift +66 -0
- package/Sources/RunicCore/Providers/Antigravity/AntigravityStatusProbe.swift +685 -0
- package/Sources/RunicCore/Providers/Auggie/AuggieProviderDescriptor.swift +83 -0
- package/Sources/RunicCore/Providers/Auggie/AuggieUsageFetcher.swift +142 -0
- package/Sources/RunicCore/Providers/Azure/AzureProviderDescriptor.swift +141 -0
- package/Sources/RunicCore/Providers/Azure/AzureUsageFetcher.swift +186 -0
- package/Sources/RunicCore/Providers/Bedrock/BedrockProviderDescriptor.swift +126 -0
- package/Sources/RunicCore/Providers/Bedrock/BedrockUsageFetcher.swift +168 -0
- package/Sources/RunicCore/Providers/Cerebras/CerebrasProviderDescriptor.swift +84 -0
- package/Sources/RunicCore/Providers/Cerebras/CerebrasUsageFetcher.swift +75 -0
- package/Sources/RunicCore/Providers/Claude/ClaudeCLISession.swift +332 -0
- package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthCredentials.swift +180 -0
- package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthUsageFetcher.swift +137 -0
- package/Sources/RunicCore/Providers/Claude/ClaudeProviderDescriptor.swift +207 -0
- package/Sources/RunicCore/Providers/Claude/ClaudeStatusProbe.swift +654 -0
- package/Sources/RunicCore/Providers/Claude/ClaudeUsageDataSource.swift +28 -0
- package/Sources/RunicCore/Providers/Claude/ClaudeUsageFetcher.swift +480 -0
- package/Sources/RunicCore/Providers/Claude/ClaudeWeb/ClaudeWebAPIFetcher.swift +780 -0
- package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthCredentials.swift +146 -0
- package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthUsageFetcher.swift +269 -0
- package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexTokenRefresher.swift +100 -0
- package/Sources/RunicCore/Providers/Codex/CodexProviderDescriptor.swift +243 -0
- package/Sources/RunicCore/Providers/Codex/CodexStatusProbe.swift +125 -0
- package/Sources/RunicCore/Providers/Codex/CodexUsageDataSource.swift +24 -0
- package/Sources/RunicCore/Providers/Codex/CodexWebDashboardStrategy.swift +181 -0
- package/Sources/RunicCore/Providers/Cohere/CohereProviderDescriptor.swift +83 -0
- package/Sources/RunicCore/Providers/Cohere/CohereUsageFetcher.swift +85 -0
- package/Sources/RunicCore/Providers/Copilot/CopilotDeviceFlow.swift +123 -0
- package/Sources/RunicCore/Providers/Copilot/CopilotGitHubCLITokenReader.swift +114 -0
- package/Sources/RunicCore/Providers/Copilot/CopilotProviderDescriptor.swift +100 -0
- package/Sources/RunicCore/Providers/Copilot/CopilotUsageFetcher.swift +291 -0
- package/Sources/RunicCore/Providers/Copilot/CopilotVSCodeTokenReader.swift +386 -0
- package/Sources/RunicCore/Providers/Cursor/CursorProviderDescriptor.swift +65 -0
- package/Sources/RunicCore/Providers/Cursor/CursorStatusProbe.swift +594 -0
- package/Sources/RunicCore/Providers/DeepSeek/DeepSeekProviderDescriptor.swift +85 -0
- package/Sources/RunicCore/Providers/DeepSeek/DeepSeekUsageFetcher.swift +108 -0
- package/Sources/RunicCore/Providers/Factory/FactoryLocalStorageImporter.swift +398 -0
- package/Sources/RunicCore/Providers/Factory/FactoryProviderDescriptor.swift +65 -0
- package/Sources/RunicCore/Providers/Factory/FactoryStatusProbe.swift +1275 -0
- package/Sources/RunicCore/Providers/Fireworks/FireworksProviderDescriptor.swift +84 -0
- package/Sources/RunicCore/Providers/Fireworks/FireworksUsageFetcher.swift +75 -0
- package/Sources/RunicCore/Providers/Gemini/GeminiProviderDescriptor.swift +65 -0
- package/Sources/RunicCore/Providers/Gemini/GeminiStatusProbe.swift +835 -0
- package/Sources/RunicCore/Providers/Groq/GroqProviderDescriptor.swift +83 -0
- package/Sources/RunicCore/Providers/Groq/GroqUsageFetcher.swift +71 -0
- package/Sources/RunicCore/Providers/Kimi/KimiProviderDescriptor.swift +83 -0
- package/Sources/RunicCore/Providers/Kimi/KimiUsageFetcher.swift +77 -0
- package/Sources/RunicCore/Providers/MiniMax/MiniMaxProviderDescriptor.swift +92 -0
- package/Sources/RunicCore/Providers/MiniMax/MiniMaxSettingsReader.swift +54 -0
- package/Sources/RunicCore/Providers/MiniMax/MiniMaxUsageFetcher.swift +171 -0
- package/Sources/RunicCore/Providers/MiniMax/MiniMaxWebUsageFetcher.swift +911 -0
- package/Sources/RunicCore/Providers/Mistral/MistralProviderDescriptor.swift +84 -0
- package/Sources/RunicCore/Providers/Mistral/MistralUsageFetcher.swift +75 -0
- package/Sources/RunicCore/Providers/OpenRouter/OpenRouterProviderDescriptor.swift +87 -0
- package/Sources/RunicCore/Providers/OpenRouter/OpenRouterUsageFetcher.swift +207 -0
- package/Sources/RunicCore/Providers/Perplexity/PerplexityProviderDescriptor.swift +84 -0
- package/Sources/RunicCore/Providers/Perplexity/PerplexityUsageFetcher.swift +75 -0
- package/Sources/RunicCore/Providers/ProviderBranding.swift +25 -0
- package/Sources/RunicCore/Providers/ProviderCLIConfig.swift +17 -0
- package/Sources/RunicCore/Providers/ProviderDescriptor.swift +129 -0
- package/Sources/RunicCore/Providers/ProviderFetchPlan.swift +263 -0
- package/Sources/RunicCore/Providers/ProviderSettingsSnapshot.swift +98 -0
- package/Sources/RunicCore/Providers/ProviderTokenResolver.swift +501 -0
- package/Sources/RunicCore/Providers/ProviderVersionDetector.swift +68 -0
- package/Sources/RunicCore/Providers/Providers.swift +184 -0
- package/Sources/RunicCore/Providers/Qwen/QwenProviderDescriptor.swift +84 -0
- package/Sources/RunicCore/Providers/Qwen/QwenSettingsReader.swift +30 -0
- package/Sources/RunicCore/Providers/Qwen/QwenUsageStats.swift +317 -0
- package/Sources/RunicCore/Providers/SambaNova/SambaNovaProviderDescriptor.swift +84 -0
- package/Sources/RunicCore/Providers/SambaNova/SambaNovaUsageFetcher.swift +75 -0
- package/Sources/RunicCore/Providers/Together/TogetherProviderDescriptor.swift +83 -0
- package/Sources/RunicCore/Providers/Together/TogetherUsageFetcher.swift +75 -0
- package/Sources/RunicCore/Providers/VertexAI/VertexAIProviderDescriptor.swift +123 -0
- package/Sources/RunicCore/Providers/VertexAI/VertexAISettingsReader.swift +48 -0
- package/Sources/RunicCore/Providers/VertexAI/VertexAIUsageFetcher.swift +144 -0
- package/Sources/RunicCore/Providers/XAI/XAIProviderDescriptor.swift +83 -0
- package/Sources/RunicCore/Providers/XAI/XAIUsageFetcher.swift +75 -0
- package/Sources/RunicCore/Providers/Zai/ZaiProviderDescriptor.swift +72 -0
- package/Sources/RunicCore/Providers/Zai/ZaiSettingsReader.swift +41 -0
- package/Sources/RunicCore/Providers/Zai/ZaiUsageStats.swift +724 -0
- package/Sources/RunicCore/Sync/BackgroundSyncManager.swift +385 -0
- package/Sources/RunicCore/Sync/SyncConflictResolver.swift +310 -0
- package/Sources/RunicCore/Sync/SyncProtocol.swift +288 -0
- package/Sources/RunicCore/Sync/SyncRecord.swift +405 -0
- package/Sources/RunicCore/Sync/SyncUsageExample.swift +294 -0
- package/Sources/RunicCore/Sync/TeamSyncRecords.swift +775 -0
- package/Sources/RunicCore/Sync/iCloudSyncEngine.swift +333 -0
- package/Sources/RunicCore/Team/TeamModels.swift +583 -0
- package/Sources/RunicCore/Team/TeamShowbackExporter.swift +495 -0
- package/Sources/RunicCore/Team/TeamStore.swift +792 -0
- package/Sources/RunicCore/TextParsing.swift +55 -0
- package/Sources/RunicCore/UsageFetcher.swift +694 -0
- package/Sources/RunicCore/UsageFormatter.swift +410 -0
- package/Sources/RunicCore/UsageLedger/ClaudeUsageLogSource.swift +329 -0
- package/Sources/RunicCore/UsageLedger/CodexUsageLogSource.swift +448 -0
- package/Sources/RunicCore/UsageLedger/OTelGenAILedgerAdapter.swift +550 -0
- package/Sources/RunicCore/UsageLedger/UsageLedger.swift +29 -0
- package/Sources/RunicCore/UsageLedger/UsageLedgerAggregator.swift +660 -0
- package/Sources/RunicCore/UsageLedger/UsageLedgerInsightsAdvisor.swift +209 -0
- package/Sources/RunicCore/UsageLedger/UsageLedgerModels.swift +417 -0
- package/Sources/RunicCore/UsageLedger/UsageLedgerProjectIdentity.swift +245 -0
- package/Sources/RunicCore/UsagePace.swift +81 -0
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageCache.swift +73 -0
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageJsonl.swift +74 -0
- package/Sources/RunicCore/Vendored/CostUsage/CostUsagePricing.swift +208 -0
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner+Claude.swift +455 -0
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner+Timestamp.swift +132 -0
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner.swift +589 -0
- package/Sources/RunicCore/WidgetSnapshot.swift +183 -0
- package/Sources/RunicMacroSupport/ProviderRegistrationMacros.swift +14 -0
- package/Sources/RunicMacros/ProviderRegistrationMacros.swift +216 -0
- package/Sources/RunicWidget/RunicWidgetBundle.swift +79 -0
- package/Sources/RunicWidget/RunicWidgetProvider.swift +283 -0
- package/Sources/RunicWidget/RunicWidgetViews.swift +680 -0
- package/Tests/RunicTests/AntigravityStatusProbeTests.swift +50 -0
- package/Tests/RunicTests/AppDelegateTests.swift +43 -0
- package/Tests/RunicTests/BrowserCookieOrderLabelTests.swift +22 -0
- package/Tests/RunicTests/CLIArgumentParsingTests.swift +70 -0
- package/Tests/RunicTests/CLICostTests.swift +65 -0
- package/Tests/RunicTests/CLIProviderSelectionTests.swift +22 -0
- package/Tests/RunicTests/CLISnapshotTests.swift +72 -0
- package/Tests/RunicTests/CLIWebFallbackTests.swift +58 -0
- package/Tests/RunicTests/ClaudeOAuthTests.swift +164 -0
- package/Tests/RunicTests/ClaudeResilienceTests.swift +30 -0
- package/Tests/RunicTests/ClaudeUsageTests.swift +370 -0
- package/Tests/RunicTests/CodexOAuthTests.swift +122 -0
- package/Tests/RunicTests/CodexUsageLogSourceTests.swift +82 -0
- package/Tests/RunicTests/CopilotTokenResolverTests.swift +75 -0
- package/Tests/RunicTests/CopilotVSCodeTokenReaderTests.swift +75 -0
- package/Tests/RunicTests/CostUsageDecodingTests.swift +394 -0
- package/Tests/RunicTests/CostUsagePricingTests.swift +50 -0
- package/Tests/RunicTests/CostUsageScannerTests.swift +700 -0
- package/Tests/RunicTests/CursorStatusProbeTests.swift +323 -0
- package/Tests/RunicTests/FactoryStatusProbeTests.swift +69 -0
- package/Tests/RunicTests/GeminiAPITestHelpers.swift +94 -0
- package/Tests/RunicTests/GeminiLoginAlertTests.swift +28 -0
- package/Tests/RunicTests/GeminiStatusProbeAPITests.swift +283 -0
- package/Tests/RunicTests/GeminiStatusProbePlanTests.swift +279 -0
- package/Tests/RunicTests/GeminiStatusProbeTests.swift +233 -0
- package/Tests/RunicTests/GeminiTestEnvironment.swift +87 -0
- package/Tests/RunicTests/GoogleWorkspaceStatusTests.swift +73 -0
- package/Tests/RunicTests/InstallOriginTests.swift +18 -0
- package/Tests/RunicTests/KeyboardShortcutsBundleTests.swift +9 -0
- package/Tests/RunicTests/LiveAccountTests.swift +24 -0
- package/Tests/RunicTests/LoadingPatternTests.swift +35 -0
- package/Tests/RunicTests/MenuCardModelTests.swift +545 -0
- package/Tests/RunicTests/MiniMaxCookieHeaderStoreTestSupport.swift +8 -0
- package/Tests/RunicTests/MiniMaxGroupIDStoreTestSupport.swift +8 -0
- package/Tests/RunicTests/MiniMaxParsingTests.swift +68 -0
- package/Tests/RunicTests/MiniMaxTokenStoreTestSupport.swift +8 -0
- package/Tests/RunicTests/OTelGenAILedgerAdapterTests.swift +112 -0
- package/Tests/RunicTests/OpenAIDashboardBrowserCookieImporterTests.swift +17 -0
- package/Tests/RunicTests/OpenAIDashboardFetcherCreditsWaitTests.swift +75 -0
- package/Tests/RunicTests/OpenAIDashboardOffscreenHostTests.swift +27 -0
- package/Tests/RunicTests/OpenAIDashboardParserTests.swift +134 -0
- package/Tests/RunicTests/OpenAIWebAccountSwitchTests.swift +53 -0
- package/Tests/RunicTests/OpenRouterTokenStoreTestSupport.swift +92 -0
- package/Tests/RunicTests/PathBuilderTests.swift +237 -0
- package/Tests/RunicTests/ProviderFetchPipelineTests.swift +160 -0
- package/Tests/RunicTests/ProviderIconResourcesTests.swift +38 -0
- package/Tests/RunicTests/ProviderMetadataStatusLinkTests.swift +16 -0
- package/Tests/RunicTests/ProviderRegistryTests.swift +29 -0
- package/Tests/RunicTests/ProviderSettingsDescriptorTests.swift +202 -0
- package/Tests/RunicTests/ProviderToggleStoreTests.swift +51 -0
- package/Tests/RunicTests/RunicTests.swift +120 -0
- package/Tests/RunicTests/SessionQuotaNotificationLogicTests.swift +36 -0
- package/Tests/RunicTests/SettingsStoreTests.swift +161 -0
- package/Tests/RunicTests/StatusItemAnimationTests.swift +49 -0
- package/Tests/RunicTests/StatusMenuTests.swift +434 -0
- package/Tests/RunicTests/StatusProbeTests.swift +377 -0
- package/Tests/RunicTests/SubprocessRunnerTests.swift +20 -0
- package/Tests/RunicTests/SubscriptionDetectionTests.swift +65 -0
- package/Tests/RunicTests/TTYCommandRunnerTests.swift +148 -0
- package/Tests/RunicTests/TTYIntegrationTests.swift +41 -0
- package/Tests/RunicTests/TeamShowbackExporterTests.swift +159 -0
- package/Tests/RunicTests/TextParsingTests.swift +12 -0
- package/Tests/RunicTests/UsageFormatterTests.swift +112 -0
- package/Tests/RunicTests/UsageLedgerAnomalyDetectionTests.swift +172 -0
- package/Tests/RunicTests/UsageLedgerForecastTests.swift +213 -0
- package/Tests/RunicTests/UsageLedgerInsightsAdvisorTests.swift +83 -0
- package/Tests/RunicTests/UsageLedgerProjectNameTests.swift +170 -0
- package/Tests/RunicTests/UsagePaceTests.swift +77 -0
- package/Tests/RunicTests/UsagePaceTextTests.swift +109 -0
- package/Tests/RunicTests/UsagePolicyEngineTests.swift +91 -0
- package/Tests/RunicTests/WidgetSnapshotTests.swift +45 -0
- package/Tests/RunicTests/ZaiProviderTests.swift +61 -0
- package/Tests/RunicTests/ZaiTokenStoreTestSupport.swift +6 -0
- package/TestsLinux/PlatformGatingTests.swift +46 -0
- package/appcast.xml +105 -0
- package/assets/logo-concept-stack.svg +24 -0
- package/assets/logo-minimal-bars.svg +15 -0
- package/assets/logo.svg +20 -0
- package/assets/logo2.svg +43 -0
- package/bin/docs-list +5 -0
- package/bin/install-runic-cli.sh +32 -0
- package/build-and-run.sh +369 -0
- package/docs/.nojekyll +1 -0
- package/docs/CNAME +1 -0
- package/docs/antigravity.md +75 -0
- package/docs/architecture.md +32 -0
- package/docs/claude.md +93 -0
- package/docs/cli-commands/integration_guide.md +371 -0
- package/docs/cli-commands/quick_reference.md +362 -0
- package/docs/cli-commands/readme.md +361 -0
- package/docs/cli.md +156 -0
- package/docs/cloudkit_sync_guide.md +495 -0
- package/docs/codebase_review.md +288 -0
- package/docs/codex-oauth.md +635 -0
- package/docs/codex.md +104 -0
- package/docs/codexbar.png +0 -0
- package/docs/copilot.md +44 -0
- package/docs/cursor.md +46 -0
- package/docs/design/designcomparisonchart.md +510 -0
- package/docs/design/implementationguide.md +792 -0
- package/docs/design/menubaricondesignconcepts.md +796 -0
- package/docs/design/mockups/hybridiconconcept.svg +62 -0
- package/docs/design/mockups/infinityiconconcept.svg +41 -0
- package/docs/design/mockups/infinityiconstates.svg +129 -0
- package/docs/design/mockups/wavelogorefined.svg +48 -0
- package/docs/design/quick_summary.md +426 -0
- package/docs/design/readme.md +478 -0
- package/docs/design/sizespecifications.md +575 -0
- package/docs/design-system.md +836 -0
- package/docs/factory.md +103 -0
- package/docs/gemini.md +73 -0
- package/docs/icon.md +37 -0
- package/docs/icon.png +0 -0
- package/docs/index.html +175 -0
- package/docs/keychain_fix.md +274 -0
- package/docs/minimax.md +71 -0
- package/docs/packaging.md +25 -0
- package/docs/progress-bar-improvements.md +240 -0
- package/docs/progress-bar-quick-reference.md +283 -0
- package/docs/progress-bar-technical-details.md +432 -0
- package/docs/progress-bar-visual-test.swift +375 -0
- package/docs/provider.md +202 -0
- package/docs/providers.md +86 -0
- package/docs/refactor/macros.md +35 -0
- package/docs/refresh-loop.md +22 -0
- package/docs/releasing-homebrew.md +35 -0
- package/docs/releasing.md +121 -0
- package/docs/research/concrete_todo_2026-02-22.md +47 -0
- package/docs/research/core-feature-research.md +248 -0
- package/docs/research/feature_uiux_roadmap_2026-02-22.md +202 -0
- package/docs/research/parity_matrix.md +49 -0
- package/docs/research/provider_expansion_candidates_2026-02-22.md +80 -0
- package/docs/research/provider_model_token_project_matrix_2026-02-23.md +46 -0
- package/docs/research/release_gate_checklist.md +57 -0
- package/docs/site.css +505 -0
- package/docs/sparkle.md +28 -0
- package/docs/status.md +28 -0
- package/docs/sync/implementation.md +393 -0
- package/docs/sync/readme.md +317 -0
- package/docs/sync_files_summary.md +391 -0
- package/docs/sync_quick_reference.md +225 -0
- package/docs/todo.md +11 -0
- package/docs/ui.md +29 -0
- package/docs/web-integration.md +9 -0
- package/docs/widgets.md +85 -0
- package/docs/workflows/error-handling-improvements.md +434 -0
- package/docs/workflows/folder_structure.md +299 -0
- package/docs/workflows/loading_states.md +446 -0
- package/docs/workflows/loading_states_examples.md +565 -0
- package/docs/workflows/loading_states_flow.md +430 -0
- package/docs/workflows/performance_optimizations.md +457 -0
- package/docs/workflows/phase1-cli-testing-report.md +313 -0
- package/docs/workflows/quick_reference.md +228 -0
- package/docs/workflows/readme.md +59 -0
- package/docs/workflows/recent_improvements.md +275 -0
- package/docs/workflows/sync_enablement_summary.md +400 -0
- package/docs/zai.md +43 -0
- package/package.json +36 -0
- package/runic.png +0 -0
- package/version.env +2 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
# Sync Infrastructure File Summary
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The sync infrastructure in `/Sources/RunicCore/Sync/` consists of 6 files that work together to provide iCloud CloudKit synchronization for Runic. This document provides a detailed summary of what each file does.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. SyncProtocol.swift
|
|
10
|
+
|
|
11
|
+
**Purpose**: Core protocol definitions and supporting types
|
|
12
|
+
|
|
13
|
+
### Key Components
|
|
14
|
+
|
|
15
|
+
#### Protocols
|
|
16
|
+
- **SyncEngine**: Main protocol for sync operations
|
|
17
|
+
- `sync(options:)` - Full bidirectional sync
|
|
18
|
+
- `push(records:)` - Push local changes to remote
|
|
19
|
+
- `fetch(recordTypes:)` - Fetch changes from remote
|
|
20
|
+
- `delete(recordIDs:)` - Delete records from remote
|
|
21
|
+
- `resetSync()` - Reset sync state
|
|
22
|
+
|
|
23
|
+
- **SyncableRecord**: Protocol for syncable objects
|
|
24
|
+
- Required properties: `recordID`, `recordType`, `version`, `modifiedAt`, `lastModifiedDeviceID`
|
|
25
|
+
- Required methods: `toCKRecord()`, `fromCKRecord(_:)`
|
|
26
|
+
- Must conform to `Sendable` and `Codable`
|
|
27
|
+
|
|
28
|
+
- **SyncConflictResolverProtocol**: Conflict resolution interface
|
|
29
|
+
- `resolve(local:remote:strategy:)` - Resolves conflicts between versions
|
|
30
|
+
|
|
31
|
+
- **SyncObserver**: Observer pattern for sync events
|
|
32
|
+
- `syncDidStart()`, `syncDidProgress(current:total:)`, `syncDidComplete(result:)`, `syncDidFail(error:)`
|
|
33
|
+
|
|
34
|
+
#### Supporting Types
|
|
35
|
+
- **SyncOptions**: Configuration for sync operations
|
|
36
|
+
- `forceFullSync`, `batchSize`, `conflictStrategy`, `backgroundMode`, `timeout`, `encryptSensitiveData`
|
|
37
|
+
|
|
38
|
+
- **SyncResult**: Statistics from sync operation
|
|
39
|
+
- `pushedCount`, `fetchedCount`, `conflictsResolved`, `deletedCount`, `duration`, `warnings`
|
|
40
|
+
|
|
41
|
+
- **ConflictResolutionStrategy**: Conflict resolution strategies
|
|
42
|
+
- `.lastWriteWins`, `.preferLocal`, `.preferRemote`, `.highestVersion`, `.merge`
|
|
43
|
+
|
|
44
|
+
- **SyncError**: Error types with localized descriptions
|
|
45
|
+
- `.iCloudAccountUnavailable`, `.networkUnavailable`, `.quotaExceeded`, `.timeout`, etc.
|
|
46
|
+
|
|
47
|
+
- **SyncPriority**: Priority levels for sync operations
|
|
48
|
+
- `.low`, `.normal`, `.high`, `.critical`
|
|
49
|
+
|
|
50
|
+
**Lines of Code**: 289
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## 2. SyncRecord.swift
|
|
55
|
+
|
|
56
|
+
**Purpose**: Concrete syncable record types with CloudKit conversion
|
|
57
|
+
|
|
58
|
+
### Key Components
|
|
59
|
+
|
|
60
|
+
#### CloudKit Record Type Constants
|
|
61
|
+
```swift
|
|
62
|
+
CloudKitRecordType.usageSnapshot
|
|
63
|
+
CloudKitRecordType.userPreferences
|
|
64
|
+
CloudKitRecordType.alertConfiguration
|
|
65
|
+
CloudKitRecordType.syncMetadata
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
#### Record Types
|
|
69
|
+
|
|
70
|
+
1. **UsageSnapshotSyncRecord**
|
|
71
|
+
- **Purpose**: Syncs usage data across devices
|
|
72
|
+
- **Fields**: providerID, primaryUsed, primaryLimit, secondaryUsed, secondaryLimit, costUSD, accountEmail (encrypted), updatedAt, deviceName, platform
|
|
73
|
+
- **Features**: Encrypts sensitive email data
|
|
74
|
+
|
|
75
|
+
2. **UserPreferencesSyncRecord**
|
|
76
|
+
- **Purpose**: Syncs user settings and preferences
|
|
77
|
+
- **Fields**: refreshInterval, enabledProviders, notificationsEnabled, autoRefreshEnabled, theme, displayFormat
|
|
78
|
+
- **Features**: Single record per user (fixed recordID)
|
|
79
|
+
|
|
80
|
+
3. **AlertConfigurationSyncRecord**
|
|
81
|
+
- **Purpose**: Syncs alert thresholds and notification settings
|
|
82
|
+
- **Fields**: providerID, warningThreshold, criticalThreshold, notificationChannels, enabled
|
|
83
|
+
- **Features**: One record per provider
|
|
84
|
+
|
|
85
|
+
#### Encryption Helpers
|
|
86
|
+
- `encryptString(_:)` - AES-GCM encryption for sensitive data
|
|
87
|
+
- `decryptString(_:)` - Decryption with error handling
|
|
88
|
+
- `getOrCreateEncryptionKey()` - Keychain-based key management
|
|
89
|
+
- `saveToKeychain(key:data:)` - Secure key storage
|
|
90
|
+
- `loadFromKeychain(key:)` - Key retrieval
|
|
91
|
+
|
|
92
|
+
**Lines of Code**: 394
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 3. iCloudSyncEngine.swift
|
|
97
|
+
|
|
98
|
+
**Purpose**: CloudKit-based synchronization engine implementation
|
|
99
|
+
|
|
100
|
+
### Key Components
|
|
101
|
+
|
|
102
|
+
#### Architecture
|
|
103
|
+
- **Actor-based**: Thread-safe concurrent access
|
|
104
|
+
- **CloudKit Integration**: Uses CKContainer and CKDatabase
|
|
105
|
+
- **Offline Support**: Queue for pending operations
|
|
106
|
+
- **Retry Logic**: Exponential backoff for network errors
|
|
107
|
+
|
|
108
|
+
#### Properties
|
|
109
|
+
- `container`: CloudKit container
|
|
110
|
+
- `database`: Private CloudKit database
|
|
111
|
+
- `conflictResolver`: Handles conflicts
|
|
112
|
+
- `pendingQueue`: Offline operation queue
|
|
113
|
+
- `changeToken`: For incremental sync
|
|
114
|
+
- `deviceID`: Unique device identifier
|
|
115
|
+
|
|
116
|
+
#### Key Methods
|
|
117
|
+
|
|
118
|
+
1. **sync(options:)**: Full bidirectional sync
|
|
119
|
+
- Checks iCloud account status
|
|
120
|
+
- Processes pending queue
|
|
121
|
+
- Fetches remote changes
|
|
122
|
+
- Detects and resolves conflicts
|
|
123
|
+
- Returns sync statistics
|
|
124
|
+
|
|
125
|
+
2. **push(records:)**: Push local changes
|
|
126
|
+
- Converts SyncableRecord to CKRecord
|
|
127
|
+
- Batch saves to CloudKit
|
|
128
|
+
- Handles CloudKit errors
|
|
129
|
+
- Returns saved record IDs
|
|
130
|
+
|
|
131
|
+
3. **fetch(recordTypes:)**: Fetch remote changes
|
|
132
|
+
- Queries CloudKit for each record type
|
|
133
|
+
- Parses CKRecords to SyncableRecords
|
|
134
|
+
- Returns fetched records
|
|
135
|
+
|
|
136
|
+
4. **delete(recordIDs:)**: Delete remote records
|
|
137
|
+
- Converts IDs to CKRecord.ID
|
|
138
|
+
- Batch deletes from CloudKit
|
|
139
|
+
- Returns deleted IDs
|
|
140
|
+
|
|
141
|
+
5. **enqueue(_:priority:)**: Queue offline operations
|
|
142
|
+
- Adds to pending queue
|
|
143
|
+
- Sorts by priority
|
|
144
|
+
|
|
145
|
+
#### Error Handling
|
|
146
|
+
- Network errors: Retry with exponential backoff
|
|
147
|
+
- Quota exceeded: Return appropriate error
|
|
148
|
+
- Authentication failures: Return auth error
|
|
149
|
+
- Conflict detection: Use conflict resolver
|
|
150
|
+
|
|
151
|
+
**Lines of Code**: 309
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 4. SyncConflictResolver.swift
|
|
156
|
+
|
|
157
|
+
**Purpose**: Default conflict resolution implementation
|
|
158
|
+
|
|
159
|
+
### Key Components
|
|
160
|
+
|
|
161
|
+
#### Architecture
|
|
162
|
+
- **Actor-based**: Thread-safe conflict resolution
|
|
163
|
+
- **Pluggable**: Custom merge handlers per record type
|
|
164
|
+
- **Statistics Tracking**: Comprehensive conflict metrics
|
|
165
|
+
|
|
166
|
+
#### Properties
|
|
167
|
+
- `conflictStats`: Tracks resolution statistics
|
|
168
|
+
- `mergeHandlers`: Custom handlers per record type
|
|
169
|
+
|
|
170
|
+
#### Conflict Resolution Strategies
|
|
171
|
+
|
|
172
|
+
1. **Last-write-wins**: Keep most recently modified
|
|
173
|
+
- Uses `modifiedAt` timestamp
|
|
174
|
+
- Version as tiebreaker
|
|
175
|
+
|
|
176
|
+
2. **Prefer local**: Always keep local version
|
|
177
|
+
|
|
178
|
+
3. **Prefer remote**: Always keep remote version
|
|
179
|
+
|
|
180
|
+
4. **Highest version**: Keep highest version number
|
|
181
|
+
- Timestamp as tiebreaker
|
|
182
|
+
|
|
183
|
+
5. **Merge**: Custom merge logic
|
|
184
|
+
- Uses registered handlers
|
|
185
|
+
- Falls back to last-write-wins
|
|
186
|
+
|
|
187
|
+
#### Default Merge Handlers
|
|
188
|
+
|
|
189
|
+
1. **UsageSnapshot**: Prefer record with most recent data
|
|
190
|
+
2. **UserPreferences**: Merge enabled providers (union)
|
|
191
|
+
3. **AlertConfiguration**: Use most conservative thresholds
|
|
192
|
+
|
|
193
|
+
#### Statistics
|
|
194
|
+
- Total conflicts resolved
|
|
195
|
+
- Conflicts by record type
|
|
196
|
+
- Conflicts by strategy
|
|
197
|
+
- Local vs remote win rate
|
|
198
|
+
- Last conflict timestamp
|
|
199
|
+
|
|
200
|
+
**Lines of Code**: 311
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 5. BackgroundSyncManager.swift
|
|
205
|
+
|
|
206
|
+
**Purpose**: Manages automatic background synchronization
|
|
207
|
+
|
|
208
|
+
### Key Components
|
|
209
|
+
|
|
210
|
+
#### Architecture
|
|
211
|
+
- **Actor-based**: Thread-safe background sync
|
|
212
|
+
- **Lifecycle-aware**: Responds to app state changes
|
|
213
|
+
- **Timer-based**: Periodic sync intervals
|
|
214
|
+
- **Observer pattern**: Notifies sync status
|
|
215
|
+
|
|
216
|
+
#### Properties
|
|
217
|
+
- `syncEngine`: Underlying sync engine
|
|
218
|
+
- `config`: Sync configuration
|
|
219
|
+
- `syncTimer`: Periodic sync timer (MainActor)
|
|
220
|
+
- `isEnabled`: Sync state
|
|
221
|
+
- `lastSyncDate`: Last successful sync
|
|
222
|
+
- `syncHistory`: Historical sync records
|
|
223
|
+
- `observers`: Registered observers
|
|
224
|
+
|
|
225
|
+
#### Configuration
|
|
226
|
+
- `activeSyncInterval`: Sync interval when active (default: 5 min)
|
|
227
|
+
- `backgroundSyncInterval`: Sync interval in background (default: 1 hour)
|
|
228
|
+
- `syncOnForeground`: Sync when app becomes active
|
|
229
|
+
- `syncOnBackground`: Sync when app enters background
|
|
230
|
+
|
|
231
|
+
#### Key Methods
|
|
232
|
+
|
|
233
|
+
1. **start()**: Starts automatic sync
|
|
234
|
+
- Enables sync
|
|
235
|
+
- Schedules first sync
|
|
236
|
+
|
|
237
|
+
2. **stop()**: Stops automatic sync
|
|
238
|
+
- Disables sync
|
|
239
|
+
- Invalidates timer
|
|
240
|
+
|
|
241
|
+
3. **syncNow(options:)**: Manual sync
|
|
242
|
+
- Notifies observers
|
|
243
|
+
- Performs sync
|
|
244
|
+
- Records history
|
|
245
|
+
- Returns result
|
|
246
|
+
|
|
247
|
+
4. **addObserver(_:)**: Register observer
|
|
248
|
+
5. **removeObserver(_:)**: Unregister observer
|
|
249
|
+
|
|
250
|
+
#### Lifecycle Integration
|
|
251
|
+
- `didBecomeActiveNotification`: Sync on foreground
|
|
252
|
+
- `didEnterBackgroundNotification`: Sync on background
|
|
253
|
+
- iOS background tasks: Complete sync before suspension
|
|
254
|
+
|
|
255
|
+
#### Statistics
|
|
256
|
+
- Last sync date
|
|
257
|
+
- Total/successful/failed syncs
|
|
258
|
+
- Success rate percentage
|
|
259
|
+
- Average sync duration
|
|
260
|
+
- Recent sync history (last 10)
|
|
261
|
+
|
|
262
|
+
**Lines of Code**: 385
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## 6. SyncUsageExample.swift
|
|
267
|
+
|
|
268
|
+
**Purpose**: Comprehensive integration examples (DEBUG only)
|
|
269
|
+
|
|
270
|
+
### Key Components
|
|
271
|
+
|
|
272
|
+
#### Example Functions
|
|
273
|
+
|
|
274
|
+
1. **setupSyncExample()**: Basic initialization
|
|
275
|
+
2. **customConfigurationExample()**: Custom config
|
|
276
|
+
3. **syncUsageDataExample()**: Sync usage records
|
|
277
|
+
4. **syncPreferencesExample()**: Sync preferences
|
|
278
|
+
5. **syncAlertConfigExample()**: Sync alerts
|
|
279
|
+
6. **manualSyncExample()**: Manual sync with options
|
|
280
|
+
7. **conflictResolutionExample()**: Custom conflict handlers
|
|
281
|
+
8. **observerExample()**: Observer pattern
|
|
282
|
+
9. **statisticsExample()**: Monitoring and stats
|
|
283
|
+
10. **errorHandlingExample()**: Error handling patterns
|
|
284
|
+
|
|
285
|
+
#### Example Observer
|
|
286
|
+
- **SyncProgressObserver**: Sample observer implementation
|
|
287
|
+
- Prints sync start, progress, completion, errors
|
|
288
|
+
- Demonstrates observer pattern
|
|
289
|
+
|
|
290
|
+
#### Coverage
|
|
291
|
+
- All record types (usage, preferences, alerts)
|
|
292
|
+
- All sync operations (push, fetch, sync, queue)
|
|
293
|
+
- All conflict strategies
|
|
294
|
+
- Custom merge handlers
|
|
295
|
+
- Statistics and monitoring
|
|
296
|
+
- Error handling patterns
|
|
297
|
+
|
|
298
|
+
**Lines of Code**: 295
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## File Dependencies
|
|
303
|
+
|
|
304
|
+
```
|
|
305
|
+
SyncProtocol.swift
|
|
306
|
+
↓
|
|
307
|
+
├── SyncRecord.swift
|
|
308
|
+
├── iCloudSyncEngine.swift
|
|
309
|
+
│ ↓
|
|
310
|
+
│ SyncConflictResolver.swift
|
|
311
|
+
│ ↓
|
|
312
|
+
│ BackgroundSyncManager.swift
|
|
313
|
+
│ ↓
|
|
314
|
+
└── SyncUsageExample.swift
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## Total Statistics
|
|
320
|
+
|
|
321
|
+
- **Total Files**: 6
|
|
322
|
+
- **Total Lines**: ~1,983 lines
|
|
323
|
+
- **Protocols Defined**: 4
|
|
324
|
+
- **Concrete Types**: 12
|
|
325
|
+
- **Enums**: 4
|
|
326
|
+
- **Supporting Functions**: 15+
|
|
327
|
+
- **Example Functions**: 10
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## Key Features
|
|
332
|
+
|
|
333
|
+
### ✅ Implemented
|
|
334
|
+
- [x] Full bidirectional sync
|
|
335
|
+
- [x] Offline queue with priorities
|
|
336
|
+
- [x] Conflict resolution (5 strategies)
|
|
337
|
+
- [x] Custom merge handlers
|
|
338
|
+
- [x] AES-GCM encryption
|
|
339
|
+
- [x] Background sync manager
|
|
340
|
+
- [x] Lifecycle integration
|
|
341
|
+
- [x] Observer pattern
|
|
342
|
+
- [x] Retry logic with backoff
|
|
343
|
+
- [x] Statistics and monitoring
|
|
344
|
+
- [x] Error handling
|
|
345
|
+
- [x] Comprehensive examples
|
|
346
|
+
|
|
347
|
+
### 🔒 Security
|
|
348
|
+
- [x] Private CloudKit database
|
|
349
|
+
- [x] Keychain-based encryption keys
|
|
350
|
+
- [x] AES-GCM for sensitive data
|
|
351
|
+
- [x] User authentication required
|
|
352
|
+
|
|
353
|
+
### ⚡ Performance
|
|
354
|
+
- [x] Actor-based concurrency
|
|
355
|
+
- [x] Batch operations
|
|
356
|
+
- [x] Incremental sync (change tokens)
|
|
357
|
+
- [x] Configurable intervals
|
|
358
|
+
- [x] Priority-based queue
|
|
359
|
+
|
|
360
|
+
### 🧪 Testing
|
|
361
|
+
- [x] DEBUG-only examples
|
|
362
|
+
- [x] Comprehensive error scenarios
|
|
363
|
+
- [x] Observer testing
|
|
364
|
+
- [x] Statistics validation
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## Usage Pattern
|
|
369
|
+
|
|
370
|
+
```swift
|
|
371
|
+
// 1. Initialize
|
|
372
|
+
let syncEngine = iCloudSyncEngine()
|
|
373
|
+
let syncManager = BackgroundSyncManager(syncEngine: syncEngine)
|
|
374
|
+
|
|
375
|
+
// 2. Configure observer
|
|
376
|
+
await syncManager.addObserver(myObserver)
|
|
377
|
+
|
|
378
|
+
// 3. Start automatic sync
|
|
379
|
+
await syncManager.start()
|
|
380
|
+
|
|
381
|
+
// 4. Create and sync records
|
|
382
|
+
let record = UsageSnapshotSyncRecord(...)
|
|
383
|
+
await syncEngine.push(records: [record])
|
|
384
|
+
|
|
385
|
+
// 5. Monitor statistics
|
|
386
|
+
let stats = await syncManager.statistics
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
**Note**: All files compile successfully with Swift 6 strict concurrency enabled. The infrastructure is production-ready and fully documented.
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# CloudKit Sync Quick Reference
|
|
2
|
+
|
|
3
|
+
## One-Minute Setup
|
|
4
|
+
|
|
5
|
+
```swift
|
|
6
|
+
import RunicCore
|
|
7
|
+
|
|
8
|
+
// 1. Initialize
|
|
9
|
+
let syncEngine = iCloudSyncEngine()
|
|
10
|
+
let syncManager = BackgroundSyncManager(syncEngine: syncEngine)
|
|
11
|
+
|
|
12
|
+
// 2. Start
|
|
13
|
+
await syncManager.start()
|
|
14
|
+
|
|
15
|
+
// Done! Sync runs automatically every 5 minutes (active) / 1 hour (background)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Common Operations
|
|
21
|
+
|
|
22
|
+
### Push Usage Data
|
|
23
|
+
```swift
|
|
24
|
+
let record = UsageSnapshotSyncRecord(
|
|
25
|
+
providerID: "claude",
|
|
26
|
+
primaryUsed: 75000,
|
|
27
|
+
primaryLimit: 100000,
|
|
28
|
+
deviceName: "MacBook Pro",
|
|
29
|
+
platform: "macOS"
|
|
30
|
+
)
|
|
31
|
+
await syncEngine.push(records: [record])
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Sync Preferences
|
|
35
|
+
```swift
|
|
36
|
+
let prefs = UserPreferencesSyncRecord(
|
|
37
|
+
refreshInterval: 300,
|
|
38
|
+
enabledProviders: ["claude", "openai"],
|
|
39
|
+
notificationsEnabled: true
|
|
40
|
+
)
|
|
41
|
+
await syncEngine.push(records: [prefs])
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Manual Sync
|
|
45
|
+
```swift
|
|
46
|
+
let result = await syncManager.syncNow()
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Force Full Sync
|
|
50
|
+
```swift
|
|
51
|
+
let options = SyncOptions(forceFullSync: true)
|
|
52
|
+
let result = await syncManager.syncNow(options: options)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Monitoring
|
|
58
|
+
|
|
59
|
+
### Check Sync Status
|
|
60
|
+
```swift
|
|
61
|
+
let stats = await syncManager.statistics
|
|
62
|
+
print("Success rate: \(stats.successRate)%")
|
|
63
|
+
print("Last sync: \(stats.lastSyncDate)")
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Add Observer
|
|
67
|
+
```swift
|
|
68
|
+
class MySyncObserver: SyncObserver {
|
|
69
|
+
func syncDidStart() { print("Syncing...") }
|
|
70
|
+
func syncDidProgress(current: Int, total: Int) { }
|
|
71
|
+
func syncDidComplete(result: SyncResult) { print("Done!") }
|
|
72
|
+
func syncDidFail(error: SyncError) { print("Failed: \(error)") }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
await syncManager.addObserver(MySyncObserver())
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Error Handling
|
|
81
|
+
|
|
82
|
+
```swift
|
|
83
|
+
switch result {
|
|
84
|
+
case .success(let syncResult):
|
|
85
|
+
print("Synced \(syncResult.pushedCount + syncResult.fetchedCount) records")
|
|
86
|
+
|
|
87
|
+
case .failure(let error):
|
|
88
|
+
switch error {
|
|
89
|
+
case .iCloudAccountUnavailable:
|
|
90
|
+
// Show "Sign in to iCloud" message
|
|
91
|
+
case .networkUnavailable:
|
|
92
|
+
// Queue for later, show offline indicator
|
|
93
|
+
case .quotaExceeded:
|
|
94
|
+
// Show "Storage full" message
|
|
95
|
+
default:
|
|
96
|
+
// Generic error handling
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Configuration
|
|
104
|
+
|
|
105
|
+
### Custom Intervals
|
|
106
|
+
```swift
|
|
107
|
+
let config = SyncConfiguration(
|
|
108
|
+
activeSyncInterval: 180, // 3 min
|
|
109
|
+
backgroundSyncInterval: 1800, // 30 min
|
|
110
|
+
syncOnForeground: true,
|
|
111
|
+
syncOnBackground: true
|
|
112
|
+
)
|
|
113
|
+
let syncManager = BackgroundSyncManager(syncEngine: syncEngine, config: config)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Custom Conflict Strategy
|
|
117
|
+
```swift
|
|
118
|
+
let options = SyncOptions(
|
|
119
|
+
conflictStrategy: .merge // or .lastWriteWins, .preferLocal, .preferRemote
|
|
120
|
+
)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## CloudKit Record Types
|
|
126
|
+
|
|
127
|
+
| Record Type | Purpose | Key Fields |
|
|
128
|
+
|------------|---------|------------|
|
|
129
|
+
| **UsageSnapshot** | Usage data | providerID, primaryUsed, primaryLimit, costUSD |
|
|
130
|
+
| **UserPreferences** | Settings | refreshInterval, enabledProviders, theme |
|
|
131
|
+
| **AlertConfiguration** | Alerts | warningThreshold, criticalThreshold, enabled |
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Conflict Resolution Strategies
|
|
136
|
+
|
|
137
|
+
| Strategy | Behavior |
|
|
138
|
+
|----------|----------|
|
|
139
|
+
| **lastWriteWins** | Most recent modification wins (default) |
|
|
140
|
+
| **preferLocal** | Always keep local version |
|
|
141
|
+
| **preferRemote** | Always keep remote version |
|
|
142
|
+
| **highestVersion** | Highest version number wins |
|
|
143
|
+
| **merge** | Custom merge logic (smart defaults included) |
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Offline Support
|
|
148
|
+
|
|
149
|
+
```swift
|
|
150
|
+
// Queue for sync when online (automatic)
|
|
151
|
+
await syncEngine.enqueue(record, priority: .high)
|
|
152
|
+
|
|
153
|
+
// Check pending operations
|
|
154
|
+
let pending = await syncEngine.pendingOperationCount
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Security
|
|
160
|
+
|
|
161
|
+
- ✅ Private CloudKit database (user-specific)
|
|
162
|
+
- ✅ AES-GCM encryption for sensitive data
|
|
163
|
+
- ✅ Keychain-based key storage
|
|
164
|
+
- ✅ User authentication required
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Troubleshooting
|
|
169
|
+
|
|
170
|
+
### "iCloud account unavailable"
|
|
171
|
+
→ Settings > Apple ID > iCloud > Enable iCloud Drive
|
|
172
|
+
|
|
173
|
+
### "Network unavailable"
|
|
174
|
+
→ Changes queued automatically, will sync when online
|
|
175
|
+
|
|
176
|
+
### Records not syncing
|
|
177
|
+
1. Check CloudKit Console for errors
|
|
178
|
+
2. Verify entitlements include CloudKit
|
|
179
|
+
3. Ensure container identifier is correct
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Performance Tips
|
|
184
|
+
|
|
185
|
+
- Default batch size: 100 records (adjust with `SyncOptions.batchSize`)
|
|
186
|
+
- Use priority queue for critical data: `.high` or `.critical`
|
|
187
|
+
- Monitor statistics to track sync performance
|
|
188
|
+
- Sync on foreground disabled if last sync < 5 min ago
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Required Setup (One-Time)
|
|
193
|
+
|
|
194
|
+
1. **Entitlements**: Add CloudKit to `Runic.entitlements`
|
|
195
|
+
2. **Container**: Create iCloud container in Developer Portal
|
|
196
|
+
3. **Schema**: Create 3 record types in CloudKit Console
|
|
197
|
+
4. **Code**: Initialize sync engine at app launch
|
|
198
|
+
|
|
199
|
+
See `CLOUDKIT_SYNC_GUIDE.md` for detailed setup instructions.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Files
|
|
204
|
+
|
|
205
|
+
- `SyncProtocol.swift` - Protocols and types
|
|
206
|
+
- `SyncRecord.swift` - Record definitions
|
|
207
|
+
- `iCloudSyncEngine.swift` - CloudKit implementation
|
|
208
|
+
- `SyncConflictResolver.swift` - Conflict resolution
|
|
209
|
+
- `BackgroundSyncManager.swift` - Automatic sync
|
|
210
|
+
- `SyncUsageExample.swift` - Integration examples
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Build Status
|
|
215
|
+
|
|
216
|
+
✅ **Compiles successfully** with Swift 6 strict concurrency
|
|
217
|
+
- Zero errors
|
|
218
|
+
- Only non-critical warnings (Codable, Timer isolation)
|
|
219
|
+
- Production ready
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
**Version**: 1.0
|
|
224
|
+
**Last Updated**: 2026-01-31
|
|
225
|
+
**Status**: Ready for integration
|
package/docs/todo.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Pending cleanup items for Runic (e.g., retire Claude Opus fallback)."
|
|
3
|
+
read_when:
|
|
4
|
+
- Grooming backlog or planning maintenance
|
|
5
|
+
- Removing legacy Claude Opus handling
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## TODO
|
|
9
|
+
|
|
10
|
+
- December 2025: remove the Claude Opus fallback logic (Claude Code) once users have fully migrated; clean up any UI labels and parsers that reference Opus as a tertiary limit.
|
|
11
|
+
- January 2026: owner-authorized roadmap item to deliver Windows and iOS app support.
|
package/docs/ui.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Menu bar UI, icon rendering, and menu layout details."
|
|
3
|
+
read_when:
|
|
4
|
+
- Changing menu layout, icon rendering, or UI copy
|
|
5
|
+
- Updating menu card or provider-specific UI
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# UI & icon
|
|
9
|
+
|
|
10
|
+
## Menu bar
|
|
11
|
+
- LSUIElement app: no Dock icon; status item uses custom NSImage.
|
|
12
|
+
- Merge Icons toggle combines providers into one status item with a switcher.
|
|
13
|
+
|
|
14
|
+
## Icon rendering
|
|
15
|
+
- 18×18 template image.
|
|
16
|
+
- Top bar = 5-hour window; bottom hairline = weekly window.
|
|
17
|
+
- Fill represents percent remaining by default; “Show usage as used” flips to percent used.
|
|
18
|
+
- Dimmed when last refresh failed; status overlays render incident indicators.
|
|
19
|
+
- Advanced: menu bar can show provider branding icons with a percent label instead of critter bars.
|
|
20
|
+
|
|
21
|
+
## Menu card
|
|
22
|
+
- Session + weekly rows with resets (relative countdown when available).
|
|
23
|
+
- Codex-only: Credits + “Buy Credits…” in-card action.
|
|
24
|
+
- Web-only rows (when OpenAI web enabled): code review remaining, usage breakdown submenu.
|
|
25
|
+
|
|
26
|
+
## Widgets (high level)
|
|
27
|
+
- Widget entries mirror the menu card; detailed pipeline in `docs/widgets.md`.
|
|
28
|
+
|
|
29
|
+
See also: `docs/widgets.md`.
|