@sriinnu/runic 2.0.0 → 2.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +256 -0
- package/LICENSE +373 -21
- package/README.md +96 -89
- package/THIRD-PARTY-NOTICES.md +651 -0
- package/package.json +14 -4
- package/.swiftformat +0 -50
- package/.swiftlint.yml +0 -160
- package/CONTRIBUTING.md +0 -456
- package/Icon.icns +0 -0
- package/Icon.icon/Assets/runic.png +0 -0
- package/Icon.icon/icon.json +0 -36
- package/Package.resolved +0 -51
- package/Package.swift +0 -136
- package/Packages/Helix/LICENSE +0 -21
- package/Packages/Helix/Package.swift +0 -29
- package/Packages/Helix/README.md +0 -976
- package/Packages/Helix/Sources/Helix/Binding.swift +0 -111
- package/Packages/Helix/Sources/Helix/CommandParser.swift +0 -160
- package/Packages/Helix/Sources/Helix/CommandSignature.swift +0 -117
- package/Packages/Helix/Sources/Helix/ExpressibleFromArgument.swift +0 -72
- package/Packages/Helix/Sources/Helix/HelpGenerator.swift +0 -175
- package/Packages/Helix/Sources/Helix/NameSpecification.swift +0 -98
- package/Packages/Helix/Sources/Helix/ParsableCommand.swift +0 -204
- package/Packages/Helix/Sources/Helix/Platform/DarwinPlatformContext.swift +0 -44
- package/Packages/Helix/Sources/Helix/Platform/LinuxPlatformContext.swift +0 -34
- package/Packages/Helix/Sources/Helix/Platform/PlatformContext+Default.swift +0 -91
- package/Packages/Helix/Sources/Helix/Platform/PlatformContext.swift +0 -94
- package/Packages/Helix/Sources/Helix/Platform/PlatformPath.swift +0 -167
- package/Packages/Helix/Sources/Helix/Platform/Stdio.swift +0 -99
- package/Packages/Helix/Sources/Helix/Platform/WebPlatformContext.swift +0 -146
- package/Packages/Helix/Sources/Helix/Platform/WindowsPlatformContext.swift +0 -97
- package/Packages/Helix/Sources/Helix/Program.swift +0 -204
- package/Packages/Helix/Sources/Helix/PropertyWrappers.swift +0 -367
- package/Packages/Silo/LICENSE +0 -21
- package/Packages/Silo/Package.swift +0 -34
- package/Packages/Silo/README.md +0 -466
- package/Packages/Silo/Sources/Silo/BinaryCookiesReader.swift +0 -169
- package/Packages/Silo/Sources/Silo/BrowserCookieAnalytics.swift +0 -365
- package/Packages/Silo/Sources/Silo/BrowserCookieBackends.swift +0 -594
- package/Packages/Silo/Sources/Silo/BrowserCookieClient.swift +0 -326
- package/Packages/Silo/Sources/Silo/BrowserCookieExport.swift +0 -154
- package/Packages/Silo/Sources/Silo/BrowserCookieImport.swift +0 -119
- package/Packages/Silo/Sources/Silo/BrowserCookieMockStore.swift +0 -121
- package/Packages/Silo/Sources/Silo/BrowserCookieModels.swift +0 -391
- package/Packages/Silo/Sources/Silo/ChromiumCookieReader.swift +0 -240
- package/Packages/Silo/Sources/Silo/CryptoSupport.swift +0 -86
- package/Packages/Silo/Sources/Silo/FirefoxCookieReader.swift +0 -172
- package/Packages/Silo/Sources/Silo/LinuxChromiumCookieReader.swift +0 -172
- package/Packages/Silo/Sources/Silo/LinuxSecretService.swift +0 -105
- package/Packages/Silo/Sources/Silo/MacOSChromiumCookieReader.swift +0 -191
- package/Packages/Silo/Sources/Silo/SQLiteSnapshot.swift +0 -41
- package/Packages/Silo/Sources/Silo/WindowsChromiumCookieReader.swift +0 -110
- package/RuniciOS/App/RuniciOSApp.swift +0 -105
- package/RuniciOS/Core/RunicTypographyiOS.swift +0 -24
- package/RuniciOS/Core/iOSUsageStore.swift +0 -192
- package/RuniciOS/Views/ProviderDetailView.swift +0 -312
- package/RuniciOS/Views/ProviderListView.swift +0 -228
- package/RuniciOS/Widgets/LargeWidget.swift +0 -367
- package/RuniciOS/Widgets/LiveActivity.swift +0 -342
- package/RuniciOS/Widgets/LockScreenWidget.swift +0 -273
- package/RuniciOS/Widgets/MediumWidget.swift +0 -370
- package/RuniciOS/Widgets/RunicWidget.swift +0 -274
- package/RuniciOS/Widgets/SmallWidget.swift +0 -281
- package/RuniciOS/Widgets/WidgetModels.swift +0 -285
- package/RuniciOS/Widgets/WidgetTimeline.swift +0 -270
- package/Scripts/CREATION-SUMMARY.md +0 -367
- package/Scripts/DIRECTORY-STRUCTURE.md +0 -358
- package/Scripts/GETTING-STARTED-CHECKLIST.md +0 -364
- package/Scripts/INDEX.md +0 -365
- package/Scripts/QUICK-REFERENCE.md +0 -164
- package/Scripts/README-SCRIPTS.md +0 -926
- package/Scripts/build-android.sh +0 -526
- package/Scripts/build-ios.sh +0 -529
- package/Scripts/build-macos.sh +0 -603
- package/Scripts/build-windows.sh +0 -504
- package/Scripts/build_icon.sh +0 -49
- package/Scripts/changelog-to-html.sh +0 -89
- package/Scripts/check-release-assets.sh +0 -10
- package/Scripts/ci-config.yml +0 -474
- package/Scripts/compile_and_run.sh +0 -219
- package/Scripts/compile_and_run_adhoc.sh +0 -4
- package/Scripts/docs-list.mjs +0 -119
- package/Scripts/make_appcast.sh +0 -58
- package/Scripts/package_app.sh +0 -409
- package/Scripts/release-lib.sh +0 -214
- package/Scripts/release.sh +0 -76
- package/Scripts/setup-all.sh +0 -387
- package/Scripts/setup-ios.sh +0 -404
- package/Scripts/setup-react-native.sh +0 -523
- package/Scripts/sign-and-notarize.sh +0 -122
- package/Scripts/test_live_update.sh +0 -38
- package/Scripts/validate_changelog.sh +0 -23
- package/Scripts/verify_appcast.sh +0 -92
- package/Sources/Runic/About.swift +0 -93
- package/Sources/Runic/AppNotifications.swift +0 -117
- package/Sources/Runic/Controllers/StatusItemController+Actions.swift +0 -670
- package/Sources/Runic/Controllers/StatusItemController+Animation.swift +0 -519
- package/Sources/Runic/Controllers/StatusItemController+ChartSubmenus.swift +0 -824
- package/Sources/Runic/Controllers/StatusItemController+CustomProviders.swift +0 -90
- package/Sources/Runic/Controllers/StatusItemController+Menu.swift +0 -1412
- package/Sources/Runic/Controllers/StatusItemController+MenuCards.swift +0 -339
- package/Sources/Runic/Controllers/StatusItemController+MenuHelpers.swift +0 -423
- package/Sources/Runic/Controllers/StatusItemController.swift +0 -360
- package/Sources/Runic/Core/BudgetNotificationManager.swift +0 -81
- package/Sources/Runic/Core/Login/ClaudeLoginRunner.swift +0 -103
- package/Sources/Runic/Core/Login/CodexLoginRunner.swift +0 -154
- package/Sources/Runic/Core/Login/CursorLoginRunner.swift +0 -206
- package/Sources/Runic/Core/Login/GeminiLoginRunner.swift +0 -92
- package/Sources/Runic/Core/Rendering/IconRenderer.swift +0 -1222
- package/Sources/Runic/Core/Rendering/IconView.swift +0 -122
- package/Sources/Runic/Core/Rendering/ProviderBrandIcon.swift +0 -71
- package/Sources/Runic/Core/RunicAnimation.swift +0 -53
- package/Sources/Runic/Core/RunicColors.swift +0 -73
- package/Sources/Runic/Core/RunicCornerRadius.swift +0 -15
- package/Sources/Runic/Core/RunicSpacing.swift +0 -68
- package/Sources/Runic/Core/RunicTypography.swift +0 -206
- package/Sources/Runic/Core/Stores/AuggieTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/AzureOpenAITokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/CerebrasTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/CohereTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/CopilotTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/CustomProviderStore.swift +0 -158
- package/Sources/Runic/Core/Stores/DeepSeekTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/FireworksTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/GroqTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/KimiTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/MiniMaxCookieHeaderStore.swift +0 -117
- package/Sources/Runic/Core/Stores/MiniMaxGroupIDStore.swift +0 -117
- package/Sources/Runic/Core/Stores/MiniMaxTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/MistralTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/OpenRouterTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/PerplexityTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/ProviderToggleStore.swift +0 -30
- package/Sources/Runic/Core/Stores/QwenTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/SambaNovaTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/SettingsStore.swift +0 -1749
- package/Sources/Runic/Core/Stores/TogetherTokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/UsageStore+Accessors.swift +0 -33
- package/Sources/Runic/Core/Stores/UsageStore+Status.swift +0 -189
- package/Sources/Runic/Core/Stores/UsageStore+TokenCost.swift +0 -33
- package/Sources/Runic/Core/Stores/UsageStore+WidgetSnapshot.swift +0 -67
- package/Sources/Runic/Core/Stores/UsageStore.swift +0 -3631
- package/Sources/Runic/Core/Stores/XAITokenStore.swift +0 -117
- package/Sources/Runic/Core/Stores/ZaiTokenStore.swift +0 -117
- package/Sources/Runic/Core/UsageExporter.swift +0 -197
- package/Sources/Runic/Date+RelativeDescription.swift +0 -21
- package/Sources/Runic/HiddenWindowView.swift +0 -32
- package/Sources/Runic/InstallOrigin.swift +0 -9
- package/Sources/Runic/KeyboardShortcuts+Names.swift +0 -6
- package/Sources/Runic/MouseLocationReader.swift +0 -65
- package/Sources/Runic/Notifications+Runic.swift +0 -6
- package/Sources/Runic/OpenAICreditsPurchaseWindowController.swift +0 -503
- package/Sources/Runic/ProviderRegistry.swift +0 -100
- package/Sources/Runic/ProviderSwitcherButtons.swift +0 -267
- package/Sources/Runic/Providers/Antigravity/AntigravityLoginFlow.swift +0 -11
- package/Sources/Runic/Providers/Antigravity/AntigravityProviderImplementation.swift +0 -14
- package/Sources/Runic/Providers/Auggie/AuggieProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/Azure/AzureProviderImplementation.swift +0 -52
- package/Sources/Runic/Providers/Bedrock/BedrockProviderImplementation.swift +0 -42
- package/Sources/Runic/Providers/Cerebras/CerebrasProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/Claude/ClaudeLoginFlow.swift +0 -26
- package/Sources/Runic/Providers/Claude/ClaudeProviderImplementation.swift +0 -14
- package/Sources/Runic/Providers/Codex/CodexLoginFlow.swift +0 -18
- package/Sources/Runic/Providers/Codex/CodexProviderImplementation.swift +0 -15
- package/Sources/Runic/Providers/Cohere/CohereProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/Copilot/CopilotLoginFlow.swift +0 -193
- package/Sources/Runic/Providers/Copilot/CopilotProviderImplementation.swift +0 -110
- package/Sources/Runic/Providers/Cursor/CursorLoginFlow.swift +0 -28
- package/Sources/Runic/Providers/Cursor/CursorProviderImplementation.swift +0 -15
- package/Sources/Runic/Providers/DeepSeek/DeepSeekProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/Factory/FactoryLoginFlow.swift +0 -12
- package/Sources/Runic/Providers/Factory/FactoryProviderImplementation.swift +0 -15
- package/Sources/Runic/Providers/Fireworks/FireworksProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/Gemini/GeminiLoginFlow.swift +0 -20
- package/Sources/Runic/Providers/Gemini/GeminiProviderImplementation.swift +0 -15
- package/Sources/Runic/Providers/Groq/GroqProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/Kimi/KimiProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/MiniMax/MiniMaxProviderImplementation.swift +0 -32
- package/Sources/Runic/Providers/Mistral/MistralProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/OpenRouter/OpenRouterProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/Perplexity/PerplexityProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/SambaNova/SambaNovaProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/Shared/ProviderCatalog.swift +0 -15
- package/Sources/Runic/Providers/Shared/ProviderImplementation.swift +0 -51
- package/Sources/Runic/Providers/Shared/ProviderImplementationRegistry.swift +0 -66
- package/Sources/Runic/Providers/Shared/ProviderLoginFlow.swift +0 -12
- package/Sources/Runic/Providers/Shared/ProviderSettingsDescriptors.swift +0 -99
- package/Sources/Runic/Providers/Shared/SystemSettingsLinks.swift +0 -18
- package/Sources/Runic/Providers/Together/TogetherProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/XAI/XAIProviderImplementation.swift +0 -24
- package/Sources/Runic/Providers/Zai/ZaiProviderImplementation.swift +0 -24
- package/Sources/Runic/Resources/Fonts/Caveat-Bold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/Caveat-Regular.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/FiraCode-Bold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/FiraCode-Light.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/FiraCode-Medium.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/FiraCode-Regular.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/FiraCode-SemiBold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/IBMPlexMono-Bold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/IBMPlexMono-Medium.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/IBMPlexMono-Regular.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/IBMPlexMono-SemiBold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/Inconsolata-Bold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/Inconsolata-Medium.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/Inconsolata-Regular.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/Inconsolata-SemiBold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/JetBrainsMono-Bold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/JetBrainsMono-Medium.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/JetBrainsMono-Regular.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/JetBrainsMono-SemiBold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/SpaceMono-Bold.ttf +0 -0
- package/Sources/Runic/Resources/Fonts/SpaceMono-Regular.ttf +0 -0
- package/Sources/Runic/Resources/ProviderIcon-antigravity.svg +0 -2
- package/Sources/Runic/Resources/ProviderIcon-auggie.svg +0 -3
- package/Sources/Runic/Resources/ProviderIcon-azure.svg +0 -5
- package/Sources/Runic/Resources/ProviderIcon-bedrock.svg +0 -7
- package/Sources/Runic/Resources/ProviderIcon-cerebras.svg +0 -3
- package/Sources/Runic/Resources/ProviderIcon-claude.svg +0 -1
- package/Sources/Runic/Resources/ProviderIcon-codex.svg +0 -1
- package/Sources/Runic/Resources/ProviderIcon-cohere.svg +0 -3
- package/Sources/Runic/Resources/ProviderIcon-copilot.svg +0 -1
- package/Sources/Runic/Resources/ProviderIcon-cursor.svg +0 -3
- package/Sources/Runic/Resources/ProviderIcon-deepseek.svg +0 -4
- package/Sources/Runic/Resources/ProviderIcon-factory.svg +0 -3
- package/Sources/Runic/Resources/ProviderIcon-fireworks.svg +0 -3
- package/Sources/Runic/Resources/ProviderIcon-gemini.svg +0 -1
- package/Sources/Runic/Resources/ProviderIcon-groq.svg +0 -1
- package/Sources/Runic/Resources/ProviderIcon-kimi.svg +0 -4
- package/Sources/Runic/Resources/ProviderIcon-minimax.svg +0 -1
- package/Sources/Runic/Resources/ProviderIcon-mistral.svg +0 -5
- package/Sources/Runic/Resources/ProviderIcon-openrouter.svg +0 -7
- package/Sources/Runic/Resources/ProviderIcon-perplexity.svg +0 -4
- package/Sources/Runic/Resources/ProviderIcon-qwen.svg +0 -9
- package/Sources/Runic/Resources/ProviderIcon-sambanova.svg +0 -4
- package/Sources/Runic/Resources/ProviderIcon-together.svg +0 -5
- package/Sources/Runic/Resources/ProviderIcon-vertexai.svg +0 -17
- package/Sources/Runic/Resources/ProviderIcon-xai.svg +0 -3
- package/Sources/Runic/Resources/ProviderIcon-zai.svg +0 -5
- package/Sources/Runic/Resources/RunicMenubarIcon.svg +0 -7
- package/Sources/Runic/Resources/provider-context-windows.json +0 -20
- package/Sources/Runic/RunicApp.swift +0 -367
- package/Sources/Runic/SessionQuotaNotifications.swift +0 -58
- package/Sources/Runic/UsagePaceText.swift +0 -52
- package/Sources/Runic/UsageProgressBar.swift +0 -228
- package/Sources/Runic/Utilities/DisplayLink.swift +0 -96
- package/Sources/Runic/Utilities/LoadingPattern.swift +0 -62
- package/Sources/Runic/Utilities/PerformanceConstants.swift +0 -85
- package/Sources/Runic/Views/Menu/AlertsMenuView.swift +0 -254
- package/Sources/Runic/Views/Menu/ChartPanelStyle.swift +0 -22
- package/Sources/Runic/Views/Menu/CostComparativeChartMenuView.swift +0 -275
- package/Sources/Runic/Views/Menu/CostHistoryChartMenuView.swift +0 -377
- package/Sources/Runic/Views/Menu/CreditsHistoryChartMenuView.swift +0 -312
- package/Sources/Runic/Views/Menu/EfficiencyMetricsMenuView.swift +0 -311
- package/Sources/Runic/Views/Menu/HeroStatCardsMenuView.swift +0 -231
- package/Sources/Runic/Views/Menu/HourlyActivityChartMenuView.swift +0 -228
- package/Sources/Runic/Views/Menu/InlineUsageChartView.swift +0 -157
- package/Sources/Runic/Views/Menu/MenuCardEntranceModifier.swift +0 -63
- package/Sources/Runic/Views/Menu/MenuCardSidebarView.swift +0 -248
- package/Sources/Runic/Views/Menu/MenuCardSkeletonView.swift +0 -104
- package/Sources/Runic/Views/Menu/MenuCardView.swift +0 -1889
- package/Sources/Runic/Views/Menu/MenuContent.swift +0 -153
- package/Sources/Runic/Views/Menu/MenuDescriptor.swift +0 -371
- package/Sources/Runic/Views/Menu/MenuHighlightStyle.swift +0 -35
- package/Sources/Runic/Views/Menu/ModelBreakdownMenuView.swift +0 -241
- package/Sources/Runic/Views/Menu/OverviewMenuView.swift +0 -281
- package/Sources/Runic/Views/Menu/ProjectBreakdownMenuView.swift +0 -214
- package/Sources/Runic/Views/Menu/ProjectBudgetMenuView.swift +0 -220
- package/Sources/Runic/Views/Menu/ProviderTabBarView.swift +0 -86
- package/Sources/Runic/Views/Menu/SubscriptionUtilizationChartMenuView.swift +0 -214
- package/Sources/Runic/Views/Menu/UsageBreakdownChartMenuView.swift +0 -398
- package/Sources/Runic/Views/Menu/UsageHeatmapMenuView.swift +0 -231
- package/Sources/Runic/Views/Menu/UsageTimelineChartMenuView.swift +0 -369
- package/Sources/Runic/Views/Menu/UsageWindowComparisonChartMenuView.swift +0 -191
- package/Sources/Runic/Views/Menu/WeeklyActivityChartMenuView.swift +0 -132
- package/Sources/Runic/Views/Performance/PerformanceDashboardView.swift +0 -621
- package/Sources/Runic/Views/Preferences/LiquidComponents.swift +0 -306
- package/Sources/Runic/Views/Preferences/PreferencesAboutPane.swift +0 -271
- package/Sources/Runic/Views/Preferences/PreferencesAdvancedPane.swift +0 -268
- package/Sources/Runic/Views/Preferences/PreferencesAlertsPane.swift +0 -418
- package/Sources/Runic/Views/Preferences/PreferencesAnalyticsPane.swift +0 -637
- package/Sources/Runic/Views/Preferences/PreferencesBudgetsPane.swift +0 -344
- package/Sources/Runic/Views/Preferences/PreferencesComponents.swift +0 -230
- package/Sources/Runic/Views/Preferences/PreferencesCustomProvidersPane.swift +0 -321
- package/Sources/Runic/Views/Preferences/PreferencesDebugPane.swift +0 -469
- package/Sources/Runic/Views/Preferences/PreferencesGeneralPane.swift +0 -250
- package/Sources/Runic/Views/Preferences/PreferencesHelpPane.swift +0 -50
- package/Sources/Runic/Views/Preferences/PreferencesIntegrationsPane.swift +0 -572
- package/Sources/Runic/Views/Preferences/PreferencesPerformancePane.swift +0 -291
- package/Sources/Runic/Views/Preferences/PreferencesProvidersPane.swift +0 -3480
- package/Sources/Runic/Views/Preferences/PreferencesSelection.swift +0 -29
- package/Sources/Runic/Views/Preferences/PreferencesSyncPane.swift +0 -61
- package/Sources/Runic/Views/Preferences/PreferencesView.swift +0 -213
- package/Sources/Runic/Views/Rating/QualityRatingView.swift +0 -238
- package/Sources/Runic/Views/Team/TeamDashboardView.swift +0 -376
- package/Sources/Runic/Views/Team/TeamInviteSheet.swift +0 -175
- package/Sources/Runic/Views/Team/TeamManagementView.swift +0 -762
- package/Sources/Runic/Views/Team/TeamMemberRow.swift +0 -181
- package/Sources/RunicCLI/CLIEntry.swift +0 -983
- package/Sources/RunicCLI/CLIRenderer.swift +0 -87
- package/Sources/RunicCLI/Commands/EnhancedUsageCommand.swift +0 -588
- package/Sources/RunicCLI/Commands/ModelsCommand.swift +0 -363
- package/Sources/RunicCLI/Commands/ProjectsCommand.swift +0 -453
- package/Sources/RunicCLI/Commands/ResetCommand.swift +0 -430
- package/Sources/RunicCLI/Commands/UsageLedgerSourceFactory.swift +0 -167
- package/Sources/RunicClaudeWatchdog/main.swift +0 -122
- package/Sources/RunicClaudeWebProbe/main.swift +0 -62
- package/Sources/RunicCore/AlertRuleStore.swift +0 -187
- package/Sources/RunicCore/BrowserCookieImportOrder.swift +0 -25
- package/Sources/RunicCore/CopilotUsageModels.swift +0 -84
- package/Sources/RunicCore/CostUsageFetcher.swift +0 -119
- package/Sources/RunicCore/CostUsageModels.swift +0 -479
- package/Sources/RunicCore/CreditsModels.swift +0 -50
- package/Sources/RunicCore/CustomProviders/CustomProviderModels.swift +0 -268
- package/Sources/RunicCore/CustomProviders/GenericProviderFetcher.swift +0 -631
- package/Sources/RunicCore/CustomProviders/ProviderTemplates.swift +0 -444
- package/Sources/RunicCore/Host/PTY/TTYCommandRunner.swift +0 -679
- package/Sources/RunicCore/Host/Process/SubprocessRunner.swift +0 -135
- package/Sources/RunicCore/Integrations/GitHubIntegration.swift +0 -173
- package/Sources/RunicCore/Logging/JSONStderrLogHandler.swift +0 -79
- package/Sources/RunicCore/Logging/OSLogLogHandler.swift +0 -86
- package/Sources/RunicCore/Logging/RunicLog.swift +0 -123
- package/Sources/RunicCore/Models/EnhancedUsageModels.swift +0 -370
- package/Sources/RunicCore/OpenAIDashboardModels.swift +0 -210
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardBrowserCookieImporter.swift +0 -676
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardFetcher.swift +0 -492
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardNavigationDelegate.swift +0 -51
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardParser.swift +0 -483
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardScrapeScript.swift +0 -558
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardWebViewCache.swift +0 -204
- package/Sources/RunicCore/OpenAIWeb/OpenAIDashboardWebsiteDataStore.swift +0 -78
- package/Sources/RunicCore/PathEnvironment.swift +0 -482
- package/Sources/RunicCore/Performance/PerformanceModels.swift +0 -371
- package/Sources/RunicCore/Performance/PerformanceStorageImpl.swift +0 -426
- package/Sources/RunicCore/Policy/UsagePolicyEngine.swift +0 -178
- package/Sources/RunicCore/ProjectBudgetStore.swift +0 -102
- package/Sources/RunicCore/ProviderCostSnapshot.swift +0 -29
- package/Sources/RunicCore/Providers/Antigravity/AntigravityProviderDescriptor.swift +0 -68
- package/Sources/RunicCore/Providers/Antigravity/AntigravityStatusProbe.swift +0 -685
- package/Sources/RunicCore/Providers/Auggie/AuggieProviderDescriptor.swift +0 -83
- package/Sources/RunicCore/Providers/Auggie/AuggieUsageFetcher.swift +0 -142
- package/Sources/RunicCore/Providers/Azure/AzureProviderDescriptor.swift +0 -141
- package/Sources/RunicCore/Providers/Azure/AzureUsageFetcher.swift +0 -188
- package/Sources/RunicCore/Providers/Bedrock/BedrockProviderDescriptor.swift +0 -126
- package/Sources/RunicCore/Providers/Bedrock/BedrockUsageFetcher.swift +0 -164
- package/Sources/RunicCore/Providers/Cerebras/CerebrasProviderDescriptor.swift +0 -84
- package/Sources/RunicCore/Providers/Cerebras/CerebrasUsageFetcher.swift +0 -75
- package/Sources/RunicCore/Providers/Claude/ClaudeCLISession.swift +0 -332
- package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthCredentials.swift +0 -180
- package/Sources/RunicCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthUsageFetcher.swift +0 -137
- package/Sources/RunicCore/Providers/Claude/ClaudeProviderDescriptor.swift +0 -209
- package/Sources/RunicCore/Providers/Claude/ClaudeStatusProbe.swift +0 -654
- package/Sources/RunicCore/Providers/Claude/ClaudeUsageDataSource.swift +0 -30
- package/Sources/RunicCore/Providers/Claude/ClaudeUsageFetcher.swift +0 -480
- package/Sources/RunicCore/Providers/Claude/ClaudeWeb/ClaudeWebAPIFetcher.swift +0 -780
- package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthCredentials.swift +0 -147
- package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexOAuthUsageFetcher.swift +0 -280
- package/Sources/RunicCore/Providers/Codex/CodexOAuth/CodexTokenRefresher.swift +0 -100
- package/Sources/RunicCore/Providers/Codex/CodexProviderDescriptor.swift +0 -245
- package/Sources/RunicCore/Providers/Codex/CodexStatusProbe.swift +0 -125
- package/Sources/RunicCore/Providers/Codex/CodexUsageDataSource.swift +0 -26
- package/Sources/RunicCore/Providers/Codex/CodexWebDashboardStrategy.swift +0 -183
- package/Sources/RunicCore/Providers/Cohere/CohereProviderDescriptor.swift +0 -83
- package/Sources/RunicCore/Providers/Cohere/CohereUsageFetcher.swift +0 -85
- package/Sources/RunicCore/Providers/Copilot/CopilotDeviceFlow.swift +0 -123
- package/Sources/RunicCore/Providers/Copilot/CopilotGitHubCLITokenReader.swift +0 -117
- package/Sources/RunicCore/Providers/Copilot/CopilotProviderDescriptor.swift +0 -100
- package/Sources/RunicCore/Providers/Copilot/CopilotUsageFetcher.swift +0 -293
- package/Sources/RunicCore/Providers/Copilot/CopilotVSCodeTokenReader.swift +0 -385
- package/Sources/RunicCore/Providers/Cursor/CursorProviderDescriptor.swift +0 -67
- package/Sources/RunicCore/Providers/Cursor/CursorStatusProbe.swift +0 -595
- package/Sources/RunicCore/Providers/DeepSeek/DeepSeekProviderDescriptor.swift +0 -85
- package/Sources/RunicCore/Providers/DeepSeek/DeepSeekUsageFetcher.swift +0 -108
- package/Sources/RunicCore/Providers/Factory/FactoryLocalStorageImporter.swift +0 -398
- package/Sources/RunicCore/Providers/Factory/FactoryProviderDescriptor.swift +0 -67
- package/Sources/RunicCore/Providers/Factory/FactoryStatusProbe.swift +0 -1276
- package/Sources/RunicCore/Providers/Fireworks/FireworksProviderDescriptor.swift +0 -84
- package/Sources/RunicCore/Providers/Fireworks/FireworksUsageFetcher.swift +0 -75
- package/Sources/RunicCore/Providers/Gemini/GeminiProviderDescriptor.swift +0 -67
- package/Sources/RunicCore/Providers/Gemini/GeminiStatusProbe.swift +0 -839
- package/Sources/RunicCore/Providers/Groq/GroqProviderDescriptor.swift +0 -83
- package/Sources/RunicCore/Providers/Groq/GroqUsageFetcher.swift +0 -71
- package/Sources/RunicCore/Providers/Kimi/KimiProviderDescriptor.swift +0 -83
- package/Sources/RunicCore/Providers/Kimi/KimiUsageFetcher.swift +0 -77
- package/Sources/RunicCore/Providers/MiniMax/MiniMaxProviderDescriptor.swift +0 -97
- package/Sources/RunicCore/Providers/MiniMax/MiniMaxSettingsReader.swift +0 -54
- package/Sources/RunicCore/Providers/MiniMax/MiniMaxUsageFetcher.swift +0 -168
- package/Sources/RunicCore/Providers/MiniMax/MiniMaxWebUsageFetcher.swift +0 -911
- package/Sources/RunicCore/Providers/Mistral/MistralProviderDescriptor.swift +0 -84
- package/Sources/RunicCore/Providers/Mistral/MistralUsageFetcher.swift +0 -75
- package/Sources/RunicCore/Providers/OpenRouter/OpenRouterProviderDescriptor.swift +0 -87
- package/Sources/RunicCore/Providers/OpenRouter/OpenRouterUsageFetcher.swift +0 -216
- package/Sources/RunicCore/Providers/Perplexity/PerplexityProviderDescriptor.swift +0 -84
- package/Sources/RunicCore/Providers/Perplexity/PerplexityUsageFetcher.swift +0 -75
- package/Sources/RunicCore/Providers/ProviderBranding.swift +0 -25
- package/Sources/RunicCore/Providers/ProviderCLIConfig.swift +0 -17
- package/Sources/RunicCore/Providers/ProviderDescriptor.swift +0 -129
- package/Sources/RunicCore/Providers/ProviderFetchPlan.swift +0 -263
- package/Sources/RunicCore/Providers/ProviderSettingsSnapshot.swift +0 -98
- package/Sources/RunicCore/Providers/ProviderTokenResolver.swift +0 -501
- package/Sources/RunicCore/Providers/ProviderVersionDetector.swift +0 -68
- package/Sources/RunicCore/Providers/Providers.swift +0 -184
- package/Sources/RunicCore/Providers/Qwen/QwenProviderDescriptor.swift +0 -86
- package/Sources/RunicCore/Providers/Qwen/QwenSettingsReader.swift +0 -30
- package/Sources/RunicCore/Providers/Qwen/QwenUsageStats.swift +0 -328
- package/Sources/RunicCore/Providers/SambaNova/SambaNovaProviderDescriptor.swift +0 -84
- package/Sources/RunicCore/Providers/SambaNova/SambaNovaUsageFetcher.swift +0 -75
- package/Sources/RunicCore/Providers/Together/TogetherProviderDescriptor.swift +0 -83
- package/Sources/RunicCore/Providers/Together/TogetherUsageFetcher.swift +0 -75
- package/Sources/RunicCore/Providers/VertexAI/VertexAIProviderDescriptor.swift +0 -123
- package/Sources/RunicCore/Providers/VertexAI/VertexAISettingsReader.swift +0 -48
- package/Sources/RunicCore/Providers/VertexAI/VertexAIUsageFetcher.swift +0 -144
- package/Sources/RunicCore/Providers/XAI/XAIProviderDescriptor.swift +0 -83
- package/Sources/RunicCore/Providers/XAI/XAIUsageFetcher.swift +0 -75
- package/Sources/RunicCore/Providers/Zai/ZaiProviderDescriptor.swift +0 -74
- package/Sources/RunicCore/Providers/Zai/ZaiSettingsReader.swift +0 -41
- package/Sources/RunicCore/Providers/Zai/ZaiUsageStats.swift +0 -745
- package/Sources/RunicCore/Sync/BackgroundSyncManager.swift +0 -384
- package/Sources/RunicCore/Sync/SyncConflictResolver.swift +0 -307
- package/Sources/RunicCore/Sync/SyncProtocol.swift +0 -287
- package/Sources/RunicCore/Sync/SyncRecord.swift +0 -402
- package/Sources/RunicCore/Sync/SyncUsageExample.swift +0 -288
- package/Sources/RunicCore/Sync/TeamSyncRecords.swift +0 -768
- package/Sources/RunicCore/Sync/iCloudSyncEngine.swift +0 -338
- package/Sources/RunicCore/Team/TeamModels.swift +0 -584
- package/Sources/RunicCore/Team/TeamShowbackExporter.swift +0 -495
- package/Sources/RunicCore/Team/TeamStore.swift +0 -809
- package/Sources/RunicCore/TextParsing.swift +0 -55
- package/Sources/RunicCore/UsageFetcher.swift +0 -694
- package/Sources/RunicCore/UsageFormatter.swift +0 -410
- package/Sources/RunicCore/UsageLedger/ClaudeUsageLogSource.swift +0 -441
- package/Sources/RunicCore/UsageLedger/CodexUsageLogSource.swift +0 -502
- package/Sources/RunicCore/UsageLedger/LedgerCache.swift +0 -161
- package/Sources/RunicCore/UsageLedger/OTelGenAILedgerAdapter.swift +0 -550
- package/Sources/RunicCore/UsageLedger/UsageLedger.swift +0 -29
- package/Sources/RunicCore/UsageLedger/UsageLedgerAggregator.swift +0 -675
- package/Sources/RunicCore/UsageLedger/UsageLedgerInsightsAdvisor.swift +0 -209
- package/Sources/RunicCore/UsageLedger/UsageLedgerModels.swift +0 -417
- package/Sources/RunicCore/UsageLedger/UsageLedgerProjectIdentity.swift +0 -284
- package/Sources/RunicCore/UsagePace.swift +0 -81
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageCache.swift +0 -73
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageJsonl.swift +0 -74
- package/Sources/RunicCore/Vendored/CostUsage/CostUsagePricing.swift +0 -208
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner+Claude.swift +0 -455
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner+Timestamp.swift +0 -132
- package/Sources/RunicCore/Vendored/CostUsage/CostUsageScanner.swift +0 -589
- package/Sources/RunicCore/WidgetSnapshot.swift +0 -183
- package/Sources/RunicMacroSupport/ProviderRegistrationMacros.swift +0 -14
- package/Sources/RunicMacros/ProviderRegistrationMacros.swift +0 -216
- package/Sources/RunicWidget/RunicWidgetBundle.swift +0 -79
- package/Sources/RunicWidget/RunicWidgetProvider.swift +0 -283
- package/Sources/RunicWidget/RunicWidgetViews.swift +0 -680
- package/Tests/RunicTests/AntigravityStatusProbeTests.swift +0 -50
- package/Tests/RunicTests/AppDelegateTests.swift +0 -48
- package/Tests/RunicTests/BrowserCookieOrderLabelTests.swift +0 -21
- package/Tests/RunicTests/CLIArgumentParsingTests.swift +0 -69
- package/Tests/RunicTests/CLICostTests.swift +0 -64
- package/Tests/RunicTests/CLIProviderSelectionTests.swift +0 -21
- package/Tests/RunicTests/CLISnapshotTests.swift +0 -71
- package/Tests/RunicTests/CLIWebFallbackTests.swift +0 -57
- package/Tests/RunicTests/ClaudeOAuthTests.swift +0 -163
- package/Tests/RunicTests/ClaudeResilienceTests.swift +0 -29
- package/Tests/RunicTests/ClaudeUsageTests.swift +0 -369
- package/Tests/RunicTests/CodexOAuthTests.swift +0 -121
- package/Tests/RunicTests/CodexUsageLogSourceTests.swift +0 -80
- package/Tests/RunicTests/CopilotTokenResolverTests.swift +0 -74
- package/Tests/RunicTests/CopilotVSCodeTokenReaderTests.swift +0 -74
- package/Tests/RunicTests/CostUsageDecodingTests.swift +0 -392
- package/Tests/RunicTests/CostUsagePricingTests.swift +0 -48
- package/Tests/RunicTests/CostUsageScannerTests.swift +0 -698
- package/Tests/RunicTests/CursorStatusProbeTests.swift +0 -322
- package/Tests/RunicTests/FactoryStatusProbeTests.swift +0 -67
- package/Tests/RunicTests/GeminiAPITestHelpers.swift +0 -94
- package/Tests/RunicTests/GeminiLoginAlertTests.swift +0 -27
- package/Tests/RunicTests/GeminiStatusProbeAPITests.swift +0 -283
- package/Tests/RunicTests/GeminiStatusProbePlanTests.swift +0 -279
- package/Tests/RunicTests/GeminiStatusProbeTests.swift +0 -232
- package/Tests/RunicTests/GeminiTestEnvironment.swift +0 -87
- package/Tests/RunicTests/GoogleWorkspaceStatusTests.swift +0 -72
- package/Tests/RunicTests/InstallOriginTests.swift +0 -17
- package/Tests/RunicTests/KeyboardShortcutsBundleTests.swift +0 -9
- package/Tests/RunicTests/LiveAccountTests.swift +0 -24
- package/Tests/RunicTests/LoadingPatternTests.swift +0 -34
- package/Tests/RunicTests/MenuCardModelTests.swift +0 -544
- package/Tests/RunicTests/MiniMaxCookieHeaderStoreTestSupport.swift +0 -11
- package/Tests/RunicTests/MiniMaxGroupIDStoreTestSupport.swift +0 -11
- package/Tests/RunicTests/MiniMaxParsingTests.swift +0 -67
- package/Tests/RunicTests/MiniMaxTokenStoreTestSupport.swift +0 -11
- package/Tests/RunicTests/OTelGenAILedgerAdapterTests.swift +0 -110
- package/Tests/RunicTests/OpenAIDashboardBrowserCookieImporterTests.swift +0 -16
- package/Tests/RunicTests/OpenAIDashboardFetcherCreditsWaitTests.swift +0 -74
- package/Tests/RunicTests/OpenAIDashboardOffscreenHostTests.swift +0 -26
- package/Tests/RunicTests/OpenAIDashboardParserTests.swift +0 -133
- package/Tests/RunicTests/OpenAIWebAccountSwitchTests.swift +0 -64
- package/Tests/RunicTests/OpenRouterTokenStoreTestSupport.swift +0 -131
- package/Tests/RunicTests/PathBuilderTests.swift +0 -236
- package/Tests/RunicTests/ProviderFetchPipelineTests.swift +0 -159
- package/Tests/RunicTests/ProviderIconResourcesTests.swift +0 -37
- package/Tests/RunicTests/ProviderMetadataStatusLinkTests.swift +0 -15
- package/Tests/RunicTests/ProviderRegistryTests.swift +0 -29
- package/Tests/RunicTests/ProviderSettingsDescriptorTests.swift +0 -236
- package/Tests/RunicTests/ProviderToggleStoreTests.swift +0 -50
- package/Tests/RunicTests/RunicTests.swift +0 -119
- package/Tests/RunicTests/SessionQuotaNotificationLogicTests.swift +0 -35
- package/Tests/RunicTests/SettingsStoreTests.swift +0 -265
- package/Tests/RunicTests/StatusItemAnimationTests.swift +0 -54
- package/Tests/RunicTests/StatusMenuTests.swift +0 -475
- package/Tests/RunicTests/StatusProbeTests.swift +0 -376
- package/Tests/RunicTests/SubprocessRunnerTests.swift +0 -18
- package/Tests/RunicTests/SubscriptionDetectionTests.swift +0 -64
- package/Tests/RunicTests/TTYCommandRunnerTests.swift +0 -147
- package/Tests/RunicTests/TTYIntegrationTests.swift +0 -41
- package/Tests/RunicTests/TeamShowbackExporterTests.swift +0 -157
- package/Tests/RunicTests/TextParsingTests.swift +0 -11
- package/Tests/RunicTests/UsageFormatterTests.swift +0 -111
- package/Tests/RunicTests/UsageLedgerAnomalyDetectionTests.swift +0 -170
- package/Tests/RunicTests/UsageLedgerForecastTests.swift +0 -211
- package/Tests/RunicTests/UsageLedgerInsightsAdvisorTests.swift +0 -81
- package/Tests/RunicTests/UsageLedgerProjectNameTests.swift +0 -168
- package/Tests/RunicTests/UsagePaceTests.swift +0 -76
- package/Tests/RunicTests/UsagePaceTextTests.swift +0 -108
- package/Tests/RunicTests/UsagePolicyEngineTests.swift +0 -89
- package/Tests/RunicTests/WidgetSnapshotTests.swift +0 -43
- package/Tests/RunicTests/ZaiProviderTests.swift +0 -59
- package/Tests/RunicTests/ZaiTokenStoreTestSupport.swift +0 -9
- package/TestsLinux/PlatformGatingTests.swift +0 -46
- package/appcast.xml +0 -104
- package/assets/logo-concept-stack.svg +0 -24
- package/assets/logo-minimal-bars.svg +0 -15
- package/assets/logo.svg +0 -20
- package/assets/logo2.svg +0 -43
- package/bin/docs-list +0 -5
- package/build-and-run.sh +0 -369
- package/docs/.nojekyll +0 -1
- package/docs/CNAME +0 -1
- package/docs/antigravity.md +0 -75
- package/docs/architecture.md +0 -32
- package/docs/claude.md +0 -93
- package/docs/cli-commands/integration_guide.md +0 -371
- package/docs/cli-commands/quick_reference.md +0 -362
- package/docs/cli-commands/readme.md +0 -361
- package/docs/cli.md +0 -156
- package/docs/cloudkit_sync_guide.md +0 -495
- package/docs/codebase_review.md +0 -288
- package/docs/codex-oauth.md +0 -635
- package/docs/codex.md +0 -104
- package/docs/codexbar.png +0 -0
- package/docs/copilot.md +0 -44
- package/docs/cursor.md +0 -46
- package/docs/design/designcomparisonchart.md +0 -510
- package/docs/design/implementationguide.md +0 -792
- package/docs/design/menubaricondesignconcepts.md +0 -796
- package/docs/design/mockups/hybridiconconcept.svg +0 -62
- package/docs/design/mockups/infinityiconconcept.svg +0 -41
- package/docs/design/mockups/infinityiconstates.svg +0 -129
- package/docs/design/mockups/wavelogorefined.svg +0 -48
- package/docs/design/quick_summary.md +0 -426
- package/docs/design/readme.md +0 -478
- package/docs/design/sizespecifications.md +0 -575
- package/docs/design-system.md +0 -836
- package/docs/factory.md +0 -103
- package/docs/gemini.md +0 -73
- package/docs/icon.md +0 -37
- package/docs/icon.png +0 -0
- package/docs/index.html +0 -175
- package/docs/keychain_fix.md +0 -274
- package/docs/minimax.md +0 -71
- package/docs/packaging.md +0 -25
- package/docs/progress-bar-improvements.md +0 -240
- package/docs/progress-bar-quick-reference.md +0 -283
- package/docs/progress-bar-technical-details.md +0 -432
- package/docs/progress-bar-visual-test.swift +0 -375
- package/docs/provider.md +0 -202
- package/docs/providers.md +0 -86
- package/docs/refactor/macros.md +0 -35
- package/docs/refresh-loop.md +0 -22
- package/docs/releasing-homebrew.md +0 -35
- package/docs/releasing.md +0 -121
- package/docs/research/concrete_todo_2026-02-22.md +0 -47
- package/docs/research/core-feature-research.md +0 -248
- package/docs/research/feature_uiux_roadmap_2026-02-22.md +0 -202
- package/docs/research/parity_matrix.md +0 -49
- package/docs/research/provider_expansion_candidates_2026-02-22.md +0 -80
- package/docs/research/provider_model_token_project_matrix_2026-02-23.md +0 -46
- package/docs/research/release_gate_checklist.md +0 -57
- package/docs/site.css +0 -505
- package/docs/sparkle.md +0 -28
- package/docs/status.md +0 -28
- package/docs/sync/implementation.md +0 -393
- package/docs/sync/readme.md +0 -317
- package/docs/sync_files_summary.md +0 -391
- package/docs/sync_quick_reference.md +0 -225
- package/docs/todo.md +0 -11
- package/docs/ui.md +0 -29
- package/docs/web-integration.md +0 -9
- package/docs/widgets.md +0 -85
- package/docs/workflows/error-handling-improvements.md +0 -434
- package/docs/workflows/folder_structure.md +0 -299
- package/docs/workflows/loading_states.md +0 -446
- package/docs/workflows/loading_states_examples.md +0 -565
- package/docs/workflows/loading_states_flow.md +0 -430
- package/docs/workflows/performance_optimizations.md +0 -457
- package/docs/workflows/phase1-cli-testing-report.md +0 -313
- package/docs/workflows/quick_reference.md +0 -228
- package/docs/workflows/readme.md +0 -59
- package/docs/workflows/recent_improvements.md +0 -275
- package/docs/workflows/sync_enablement_summary.md +0 -400
- package/docs/zai.md +0 -43
- package/runic.png +0 -0
- package/runic.svg +0 -15
- package/version.env +0 -2
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
import RunicCore
|
|
3
|
-
import Security
|
|
4
|
-
|
|
5
|
-
protocol AuggieTokenStoring: Sendable {
|
|
6
|
-
func loadToken() throws -> String?
|
|
7
|
-
func storeToken(_ token: String?) throws
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
enum AuggieTokenStoreError: LocalizedError {
|
|
11
|
-
case keychainStatus(OSStatus)
|
|
12
|
-
case invalidData
|
|
13
|
-
|
|
14
|
-
var errorDescription: String? {
|
|
15
|
-
switch self {
|
|
16
|
-
case let .keychainStatus(status):
|
|
17
|
-
"Keychain error: \(status)"
|
|
18
|
-
case .invalidData:
|
|
19
|
-
"Keychain returned invalid data."
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
struct KeychainAuggieTokenStore: AuggieTokenStoring {
|
|
25
|
-
private static let log = RunicLog.logger("auggie-token-store")
|
|
26
|
-
|
|
27
|
-
private let service = "com.sriinnu.athena.Runic"
|
|
28
|
-
private let account = "auggie-api-token"
|
|
29
|
-
|
|
30
|
-
func loadToken() throws -> String? {
|
|
31
|
-
// Try standard keychain first.
|
|
32
|
-
if let token = try self.readToken(dataProtection: false) {
|
|
33
|
-
return token
|
|
34
|
-
}
|
|
35
|
-
// Migrate from the old Data Protection keychain if present.
|
|
36
|
-
if let token = try self.readToken(dataProtection: true) {
|
|
37
|
-
Self.log.info("Migrating Auggie token from Data Protection keychain")
|
|
38
|
-
// Store first, delete old only on success — prevents data loss.
|
|
39
|
-
if (try? self.storeToken(token)) != nil {
|
|
40
|
-
try? self.deleteToken(dataProtection: true)
|
|
41
|
-
}
|
|
42
|
-
return token
|
|
43
|
-
}
|
|
44
|
-
return nil
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
func storeToken(_ token: String?) throws {
|
|
48
|
-
let cleaned = token?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
49
|
-
if cleaned == nil || cleaned?.isEmpty == true {
|
|
50
|
-
try? self.deleteToken(dataProtection: false)
|
|
51
|
-
try? self.deleteToken(dataProtection: true)
|
|
52
|
-
return
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
let data = cleaned!.data(using: .utf8)!
|
|
56
|
-
|
|
57
|
-
// Always delete-then-add to ensure SecAccess ACL is set.
|
|
58
|
-
// SecItemUpdate does NOT update the ACL, so existing items with
|
|
59
|
-
// missing or stale ACLs would continue to prompt for passwords.
|
|
60
|
-
try? self.deleteToken(dataProtection: false)
|
|
61
|
-
try? self.deleteToken(dataProtection: true)
|
|
62
|
-
|
|
63
|
-
var addQuery = self.baseQuery(dataProtection: false)
|
|
64
|
-
addQuery[kSecValueData as String] = data
|
|
65
|
-
addQuery[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock
|
|
66
|
-
|
|
67
|
-
let addStatus = SecItemAdd(addQuery as CFDictionary, nil)
|
|
68
|
-
guard addStatus == errSecSuccess else {
|
|
69
|
-
Self.log.error("Keychain add failed: \(addStatus)")
|
|
70
|
-
throw AuggieTokenStoreError.keychainStatus(addStatus)
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// MARK: - Private
|
|
75
|
-
|
|
76
|
-
private func readToken(dataProtection: Bool) throws -> String? {
|
|
77
|
-
var result: CFTypeRef?
|
|
78
|
-
var query = self.baseQuery(dataProtection: dataProtection)
|
|
79
|
-
query[kSecMatchLimit as String] = kSecMatchLimitOne
|
|
80
|
-
query[kSecReturnData as String] = true
|
|
81
|
-
query[kSecUseAuthenticationUI as String] = kSecUseAuthenticationUIFail
|
|
82
|
-
|
|
83
|
-
let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
84
|
-
if status == errSecItemNotFound || status == errSecInteractionNotAllowed {
|
|
85
|
-
return nil
|
|
86
|
-
}
|
|
87
|
-
guard status == errSecSuccess else {
|
|
88
|
-
Self.log.error("Keychain read failed: \(status)")
|
|
89
|
-
throw AuggieTokenStoreError.keychainStatus(status)
|
|
90
|
-
}
|
|
91
|
-
guard let data = result as? Data else {
|
|
92
|
-
throw AuggieTokenStoreError.invalidData
|
|
93
|
-
}
|
|
94
|
-
let token = String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
95
|
-
return (token?.isEmpty ?? true) ? nil : token
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
private func deleteToken(dataProtection: Bool) throws {
|
|
99
|
-
let query = self.baseQuery(dataProtection: dataProtection)
|
|
100
|
-
let status = SecItemDelete(query as CFDictionary)
|
|
101
|
-
if status == errSecSuccess || status == errSecItemNotFound { return }
|
|
102
|
-
Self.log.error("Keychain delete failed: \(status)")
|
|
103
|
-
throw AuggieTokenStoreError.keychainStatus(status)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
private func baseQuery(dataProtection: Bool) -> [String: Any] {
|
|
107
|
-
var q: [String: Any] = [
|
|
108
|
-
kSecClass as String: kSecClassGenericPassword,
|
|
109
|
-
kSecAttrService as String: self.service,
|
|
110
|
-
kSecAttrAccount as String: self.account,
|
|
111
|
-
]
|
|
112
|
-
if dataProtection {
|
|
113
|
-
q[kSecUseDataProtectionKeychain as String] = true
|
|
114
|
-
}
|
|
115
|
-
return q
|
|
116
|
-
}
|
|
117
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
import RunicCore
|
|
3
|
-
import Security
|
|
4
|
-
|
|
5
|
-
protocol AzureOpenAITokenStoring: Sendable {
|
|
6
|
-
func loadToken() throws -> String?
|
|
7
|
-
func storeToken(_ token: String?) throws
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
enum AzureOpenAITokenStoreError: LocalizedError {
|
|
11
|
-
case keychainStatus(OSStatus)
|
|
12
|
-
case invalidData
|
|
13
|
-
|
|
14
|
-
var errorDescription: String? {
|
|
15
|
-
switch self {
|
|
16
|
-
case let .keychainStatus(status):
|
|
17
|
-
"Keychain error: \(status)"
|
|
18
|
-
case .invalidData:
|
|
19
|
-
"Keychain returned invalid data."
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
struct KeychainAzureOpenAITokenStore: AzureOpenAITokenStoring {
|
|
25
|
-
private static let log = RunicLog.logger("azure-openai-token-store")
|
|
26
|
-
|
|
27
|
-
private let service = "com.sriinnu.athena.Runic"
|
|
28
|
-
private let account = "azure-openai-api-token"
|
|
29
|
-
|
|
30
|
-
func loadToken() throws -> String? {
|
|
31
|
-
// Try standard keychain first.
|
|
32
|
-
if let token = try self.readToken(dataProtection: false) {
|
|
33
|
-
return token
|
|
34
|
-
}
|
|
35
|
-
// Migrate from the old Data Protection keychain if present.
|
|
36
|
-
if let token = try self.readToken(dataProtection: true) {
|
|
37
|
-
Self.log.info("Migrating Azure OpenAI token from Data Protection keychain")
|
|
38
|
-
// Store first, delete old only on success — prevents data loss.
|
|
39
|
-
if (try? self.storeToken(token)) != nil {
|
|
40
|
-
try? self.deleteToken(dataProtection: true)
|
|
41
|
-
}
|
|
42
|
-
return token
|
|
43
|
-
}
|
|
44
|
-
return nil
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
func storeToken(_ token: String?) throws {
|
|
48
|
-
let cleaned = token?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
49
|
-
if cleaned == nil || cleaned?.isEmpty == true {
|
|
50
|
-
try? self.deleteToken(dataProtection: false)
|
|
51
|
-
try? self.deleteToken(dataProtection: true)
|
|
52
|
-
return
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
let data = cleaned!.data(using: .utf8)!
|
|
56
|
-
|
|
57
|
-
// Always delete-then-add to ensure SecAccess ACL is set.
|
|
58
|
-
// SecItemUpdate does NOT update the ACL, so existing items with
|
|
59
|
-
// missing or stale ACLs would continue to prompt for passwords.
|
|
60
|
-
try? self.deleteToken(dataProtection: false)
|
|
61
|
-
try? self.deleteToken(dataProtection: true)
|
|
62
|
-
|
|
63
|
-
var addQuery = self.baseQuery(dataProtection: false)
|
|
64
|
-
addQuery[kSecValueData as String] = data
|
|
65
|
-
addQuery[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock
|
|
66
|
-
|
|
67
|
-
let addStatus = SecItemAdd(addQuery as CFDictionary, nil)
|
|
68
|
-
guard addStatus == errSecSuccess else {
|
|
69
|
-
Self.log.error("Keychain add failed: \(addStatus)")
|
|
70
|
-
throw AzureOpenAITokenStoreError.keychainStatus(addStatus)
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// MARK: - Private
|
|
75
|
-
|
|
76
|
-
private func readToken(dataProtection: Bool) throws -> String? {
|
|
77
|
-
var result: CFTypeRef?
|
|
78
|
-
var query = self.baseQuery(dataProtection: dataProtection)
|
|
79
|
-
query[kSecMatchLimit as String] = kSecMatchLimitOne
|
|
80
|
-
query[kSecReturnData as String] = true
|
|
81
|
-
query[kSecUseAuthenticationUI as String] = kSecUseAuthenticationUIFail
|
|
82
|
-
|
|
83
|
-
let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
84
|
-
if status == errSecItemNotFound || status == errSecInteractionNotAllowed {
|
|
85
|
-
return nil
|
|
86
|
-
}
|
|
87
|
-
guard status == errSecSuccess else {
|
|
88
|
-
Self.log.error("Keychain read failed: \(status)")
|
|
89
|
-
throw AzureOpenAITokenStoreError.keychainStatus(status)
|
|
90
|
-
}
|
|
91
|
-
guard let data = result as? Data else {
|
|
92
|
-
throw AzureOpenAITokenStoreError.invalidData
|
|
93
|
-
}
|
|
94
|
-
let token = String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
95
|
-
return (token?.isEmpty ?? true) ? nil : token
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
private func deleteToken(dataProtection: Bool) throws {
|
|
99
|
-
let query = self.baseQuery(dataProtection: dataProtection)
|
|
100
|
-
let status = SecItemDelete(query as CFDictionary)
|
|
101
|
-
if status == errSecSuccess || status == errSecItemNotFound { return }
|
|
102
|
-
Self.log.error("Keychain delete failed: \(status)")
|
|
103
|
-
throw AzureOpenAITokenStoreError.keychainStatus(status)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
private func baseQuery(dataProtection: Bool) -> [String: Any] {
|
|
107
|
-
var q: [String: Any] = [
|
|
108
|
-
kSecClass as String: kSecClassGenericPassword,
|
|
109
|
-
kSecAttrService as String: self.service,
|
|
110
|
-
kSecAttrAccount as String: self.account,
|
|
111
|
-
]
|
|
112
|
-
if dataProtection {
|
|
113
|
-
q[kSecUseDataProtectionKeychain as String] = true
|
|
114
|
-
}
|
|
115
|
-
return q
|
|
116
|
-
}
|
|
117
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
import RunicCore
|
|
3
|
-
import Security
|
|
4
|
-
|
|
5
|
-
protocol CerebrasTokenStoring: Sendable {
|
|
6
|
-
func loadToken() throws -> String?
|
|
7
|
-
func storeToken(_ token: String?) throws
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
enum CerebrasTokenStoreError: LocalizedError {
|
|
11
|
-
case keychainStatus(OSStatus)
|
|
12
|
-
case invalidData
|
|
13
|
-
|
|
14
|
-
var errorDescription: String? {
|
|
15
|
-
switch self {
|
|
16
|
-
case let .keychainStatus(status):
|
|
17
|
-
"Keychain error: \(status)"
|
|
18
|
-
case .invalidData:
|
|
19
|
-
"Keychain returned invalid data."
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
struct KeychainCerebrasTokenStore: CerebrasTokenStoring {
|
|
25
|
-
private static let log = RunicLog.logger("cerebras-token-store")
|
|
26
|
-
|
|
27
|
-
private let service = "com.sriinnu.athena.Runic"
|
|
28
|
-
private let account = "cerebras-api-token"
|
|
29
|
-
|
|
30
|
-
func loadToken() throws -> String? {
|
|
31
|
-
// Try standard keychain first.
|
|
32
|
-
if let token = try self.readToken(dataProtection: false) {
|
|
33
|
-
return token
|
|
34
|
-
}
|
|
35
|
-
// Migrate from the old Data Protection keychain if present.
|
|
36
|
-
if let token = try self.readToken(dataProtection: true) {
|
|
37
|
-
Self.log.info("Migrating Cerebras token from Data Protection keychain")
|
|
38
|
-
// Store first, delete old only on success — prevents data loss.
|
|
39
|
-
if (try? self.storeToken(token)) != nil {
|
|
40
|
-
try? self.deleteToken(dataProtection: true)
|
|
41
|
-
}
|
|
42
|
-
return token
|
|
43
|
-
}
|
|
44
|
-
return nil
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
func storeToken(_ token: String?) throws {
|
|
48
|
-
let cleaned = token?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
49
|
-
if cleaned == nil || cleaned?.isEmpty == true {
|
|
50
|
-
try? self.deleteToken(dataProtection: false)
|
|
51
|
-
try? self.deleteToken(dataProtection: true)
|
|
52
|
-
return
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
let data = cleaned!.data(using: .utf8)!
|
|
56
|
-
|
|
57
|
-
// Always delete-then-add to ensure SecAccess ACL is set.
|
|
58
|
-
// SecItemUpdate does NOT update the ACL, so existing items with
|
|
59
|
-
// missing or stale ACLs would continue to prompt for passwords.
|
|
60
|
-
try? self.deleteToken(dataProtection: false)
|
|
61
|
-
try? self.deleteToken(dataProtection: true)
|
|
62
|
-
|
|
63
|
-
var addQuery = self.baseQuery(dataProtection: false)
|
|
64
|
-
addQuery[kSecValueData as String] = data
|
|
65
|
-
addQuery[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock
|
|
66
|
-
|
|
67
|
-
let addStatus = SecItemAdd(addQuery as CFDictionary, nil)
|
|
68
|
-
guard addStatus == errSecSuccess else {
|
|
69
|
-
Self.log.error("Keychain add failed: \(addStatus)")
|
|
70
|
-
throw CerebrasTokenStoreError.keychainStatus(addStatus)
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// MARK: - Private
|
|
75
|
-
|
|
76
|
-
private func readToken(dataProtection: Bool) throws -> String? {
|
|
77
|
-
var result: CFTypeRef?
|
|
78
|
-
var query = self.baseQuery(dataProtection: dataProtection)
|
|
79
|
-
query[kSecMatchLimit as String] = kSecMatchLimitOne
|
|
80
|
-
query[kSecReturnData as String] = true
|
|
81
|
-
query[kSecUseAuthenticationUI as String] = kSecUseAuthenticationUIFail
|
|
82
|
-
|
|
83
|
-
let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
84
|
-
if status == errSecItemNotFound || status == errSecInteractionNotAllowed {
|
|
85
|
-
return nil
|
|
86
|
-
}
|
|
87
|
-
guard status == errSecSuccess else {
|
|
88
|
-
Self.log.error("Keychain read failed: \(status)")
|
|
89
|
-
throw CerebrasTokenStoreError.keychainStatus(status)
|
|
90
|
-
}
|
|
91
|
-
guard let data = result as? Data else {
|
|
92
|
-
throw CerebrasTokenStoreError.invalidData
|
|
93
|
-
}
|
|
94
|
-
let token = String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
95
|
-
return (token?.isEmpty ?? true) ? nil : token
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
private func deleteToken(dataProtection: Bool) throws {
|
|
99
|
-
let query = self.baseQuery(dataProtection: dataProtection)
|
|
100
|
-
let status = SecItemDelete(query as CFDictionary)
|
|
101
|
-
if status == errSecSuccess || status == errSecItemNotFound { return }
|
|
102
|
-
Self.log.error("Keychain delete failed: \(status)")
|
|
103
|
-
throw CerebrasTokenStoreError.keychainStatus(status)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
private func baseQuery(dataProtection: Bool) -> [String: Any] {
|
|
107
|
-
var q: [String: Any] = [
|
|
108
|
-
kSecClass as String: kSecClassGenericPassword,
|
|
109
|
-
kSecAttrService as String: self.service,
|
|
110
|
-
kSecAttrAccount as String: self.account,
|
|
111
|
-
]
|
|
112
|
-
if dataProtection {
|
|
113
|
-
q[kSecUseDataProtectionKeychain as String] = true
|
|
114
|
-
}
|
|
115
|
-
return q
|
|
116
|
-
}
|
|
117
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
import RunicCore
|
|
3
|
-
import Security
|
|
4
|
-
|
|
5
|
-
protocol CohereTokenStoring: Sendable {
|
|
6
|
-
func loadToken() throws -> String?
|
|
7
|
-
func storeToken(_ token: String?) throws
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
enum CohereTokenStoreError: LocalizedError {
|
|
11
|
-
case keychainStatus(OSStatus)
|
|
12
|
-
case invalidData
|
|
13
|
-
|
|
14
|
-
var errorDescription: String? {
|
|
15
|
-
switch self {
|
|
16
|
-
case let .keychainStatus(status):
|
|
17
|
-
"Keychain error: \(status)"
|
|
18
|
-
case .invalidData:
|
|
19
|
-
"Keychain returned invalid data."
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
struct KeychainCohereTokenStore: CohereTokenStoring {
|
|
25
|
-
private static let log = RunicLog.logger("cohere-token-store")
|
|
26
|
-
|
|
27
|
-
private let service = "com.sriinnu.athena.Runic"
|
|
28
|
-
private let account = "cohere-api-token"
|
|
29
|
-
|
|
30
|
-
func loadToken() throws -> String? {
|
|
31
|
-
// Try standard keychain first.
|
|
32
|
-
if let token = try self.readToken(dataProtection: false) {
|
|
33
|
-
return token
|
|
34
|
-
}
|
|
35
|
-
// Migrate from the old Data Protection keychain if present.
|
|
36
|
-
if let token = try self.readToken(dataProtection: true) {
|
|
37
|
-
Self.log.info("Migrating Cohere token from Data Protection keychain")
|
|
38
|
-
// Store first, delete old only on success — prevents data loss.
|
|
39
|
-
if (try? self.storeToken(token)) != nil {
|
|
40
|
-
try? self.deleteToken(dataProtection: true)
|
|
41
|
-
}
|
|
42
|
-
return token
|
|
43
|
-
}
|
|
44
|
-
return nil
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
func storeToken(_ token: String?) throws {
|
|
48
|
-
let cleaned = token?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
49
|
-
if cleaned == nil || cleaned?.isEmpty == true {
|
|
50
|
-
try? self.deleteToken(dataProtection: false)
|
|
51
|
-
try? self.deleteToken(dataProtection: true)
|
|
52
|
-
return
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
let data = cleaned!.data(using: .utf8)!
|
|
56
|
-
|
|
57
|
-
// Always delete-then-add to ensure SecAccess ACL is set.
|
|
58
|
-
// SecItemUpdate does NOT update the ACL, so existing items with
|
|
59
|
-
// missing or stale ACLs would continue to prompt for passwords.
|
|
60
|
-
try? self.deleteToken(dataProtection: false)
|
|
61
|
-
try? self.deleteToken(dataProtection: true)
|
|
62
|
-
|
|
63
|
-
var addQuery = self.baseQuery(dataProtection: false)
|
|
64
|
-
addQuery[kSecValueData as String] = data
|
|
65
|
-
addQuery[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock
|
|
66
|
-
|
|
67
|
-
let addStatus = SecItemAdd(addQuery as CFDictionary, nil)
|
|
68
|
-
guard addStatus == errSecSuccess else {
|
|
69
|
-
Self.log.error("Keychain add failed: \(addStatus)")
|
|
70
|
-
throw CohereTokenStoreError.keychainStatus(addStatus)
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// MARK: - Private
|
|
75
|
-
|
|
76
|
-
private func readToken(dataProtection: Bool) throws -> String? {
|
|
77
|
-
var result: CFTypeRef?
|
|
78
|
-
var query = self.baseQuery(dataProtection: dataProtection)
|
|
79
|
-
query[kSecMatchLimit as String] = kSecMatchLimitOne
|
|
80
|
-
query[kSecReturnData as String] = true
|
|
81
|
-
query[kSecUseAuthenticationUI as String] = kSecUseAuthenticationUIFail
|
|
82
|
-
|
|
83
|
-
let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
84
|
-
if status == errSecItemNotFound || status == errSecInteractionNotAllowed {
|
|
85
|
-
return nil
|
|
86
|
-
}
|
|
87
|
-
guard status == errSecSuccess else {
|
|
88
|
-
Self.log.error("Keychain read failed: \(status)")
|
|
89
|
-
throw CohereTokenStoreError.keychainStatus(status)
|
|
90
|
-
}
|
|
91
|
-
guard let data = result as? Data else {
|
|
92
|
-
throw CohereTokenStoreError.invalidData
|
|
93
|
-
}
|
|
94
|
-
let token = String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
95
|
-
return (token?.isEmpty ?? true) ? nil : token
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
private func deleteToken(dataProtection: Bool) throws {
|
|
99
|
-
let query = self.baseQuery(dataProtection: dataProtection)
|
|
100
|
-
let status = SecItemDelete(query as CFDictionary)
|
|
101
|
-
if status == errSecSuccess || status == errSecItemNotFound { return }
|
|
102
|
-
Self.log.error("Keychain delete failed: \(status)")
|
|
103
|
-
throw CohereTokenStoreError.keychainStatus(status)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
private func baseQuery(dataProtection: Bool) -> [String: Any] {
|
|
107
|
-
var q: [String: Any] = [
|
|
108
|
-
kSecClass as String: kSecClassGenericPassword,
|
|
109
|
-
kSecAttrService as String: self.service,
|
|
110
|
-
kSecAttrAccount as String: self.account,
|
|
111
|
-
]
|
|
112
|
-
if dataProtection {
|
|
113
|
-
q[kSecUseDataProtectionKeychain as String] = true
|
|
114
|
-
}
|
|
115
|
-
return q
|
|
116
|
-
}
|
|
117
|
-
}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
import RunicCore
|
|
3
|
-
import Security
|
|
4
|
-
|
|
5
|
-
protocol CopilotTokenStoring: Sendable {
|
|
6
|
-
func loadToken() throws -> String?
|
|
7
|
-
func storeToken(_ token: String?) throws
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
enum CopilotTokenStoreError: LocalizedError {
|
|
11
|
-
case keychainStatus(OSStatus)
|
|
12
|
-
case invalidData
|
|
13
|
-
|
|
14
|
-
var errorDescription: String? {
|
|
15
|
-
switch self {
|
|
16
|
-
case let .keychainStatus(status):
|
|
17
|
-
"Keychain error: \(status)"
|
|
18
|
-
case .invalidData:
|
|
19
|
-
"Keychain returned invalid data."
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
struct KeychainCopilotTokenStore: CopilotTokenStoring {
|
|
25
|
-
private static let log = RunicLog.logger("copilot-token-store")
|
|
26
|
-
|
|
27
|
-
private let service = "com.sriinnu.athena.Runic"
|
|
28
|
-
private let account = "copilot-api-token"
|
|
29
|
-
|
|
30
|
-
func loadToken() throws -> String? {
|
|
31
|
-
// Try standard keychain first.
|
|
32
|
-
if let token = try self.readToken(dataProtection: false) {
|
|
33
|
-
return token
|
|
34
|
-
}
|
|
35
|
-
// Migrate from the old Data Protection keychain if present.
|
|
36
|
-
if let token = try self.readToken(dataProtection: true) {
|
|
37
|
-
Self.log.info("Migrating Copilot token from Data Protection keychain")
|
|
38
|
-
// Store first, delete old only on success — prevents data loss.
|
|
39
|
-
if (try? self.storeToken(token)) != nil {
|
|
40
|
-
try? self.deleteToken(dataProtection: true)
|
|
41
|
-
}
|
|
42
|
-
return token
|
|
43
|
-
}
|
|
44
|
-
return nil
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
func storeToken(_ token: String?) throws {
|
|
48
|
-
let cleaned = token?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
49
|
-
if cleaned == nil || cleaned?.isEmpty == true {
|
|
50
|
-
try? self.deleteToken(dataProtection: false)
|
|
51
|
-
try? self.deleteToken(dataProtection: true)
|
|
52
|
-
return
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
let data = cleaned!.data(using: .utf8)!
|
|
56
|
-
|
|
57
|
-
// Always delete-then-add to ensure SecAccess ACL is set.
|
|
58
|
-
// SecItemUpdate does NOT update the ACL, so existing items with
|
|
59
|
-
// missing or stale ACLs would continue to prompt for passwords.
|
|
60
|
-
try? self.deleteToken(dataProtection: false)
|
|
61
|
-
try? self.deleteToken(dataProtection: true)
|
|
62
|
-
|
|
63
|
-
var addQuery = self.baseQuery(dataProtection: false)
|
|
64
|
-
addQuery[kSecValueData as String] = data
|
|
65
|
-
addQuery[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock
|
|
66
|
-
|
|
67
|
-
let addStatus = SecItemAdd(addQuery as CFDictionary, nil)
|
|
68
|
-
guard addStatus == errSecSuccess else {
|
|
69
|
-
Self.log.error("Keychain add failed: \(addStatus)")
|
|
70
|
-
throw CopilotTokenStoreError.keychainStatus(addStatus)
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// MARK: - Private
|
|
75
|
-
|
|
76
|
-
private func readToken(dataProtection: Bool) throws -> String? {
|
|
77
|
-
var result: CFTypeRef?
|
|
78
|
-
var query = self.baseQuery(dataProtection: dataProtection)
|
|
79
|
-
query[kSecMatchLimit as String] = kSecMatchLimitOne
|
|
80
|
-
query[kSecReturnData as String] = true
|
|
81
|
-
query[kSecUseAuthenticationUI as String] = kSecUseAuthenticationUIFail
|
|
82
|
-
|
|
83
|
-
let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
84
|
-
if status == errSecItemNotFound || status == errSecInteractionNotAllowed {
|
|
85
|
-
return nil
|
|
86
|
-
}
|
|
87
|
-
guard status == errSecSuccess else {
|
|
88
|
-
Self.log.error("Keychain read failed: \(status)")
|
|
89
|
-
throw CopilotTokenStoreError.keychainStatus(status)
|
|
90
|
-
}
|
|
91
|
-
guard let data = result as? Data else {
|
|
92
|
-
throw CopilotTokenStoreError.invalidData
|
|
93
|
-
}
|
|
94
|
-
let token = String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
95
|
-
return (token?.isEmpty ?? true) ? nil : token
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
private func deleteToken(dataProtection: Bool) throws {
|
|
99
|
-
let query = self.baseQuery(dataProtection: dataProtection)
|
|
100
|
-
let status = SecItemDelete(query as CFDictionary)
|
|
101
|
-
if status == errSecSuccess || status == errSecItemNotFound { return }
|
|
102
|
-
Self.log.error("Keychain delete failed: \(status)")
|
|
103
|
-
throw CopilotTokenStoreError.keychainStatus(status)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
private func baseQuery(dataProtection: Bool) -> [String: Any] {
|
|
107
|
-
var q: [String: Any] = [
|
|
108
|
-
kSecClass as String: kSecClassGenericPassword,
|
|
109
|
-
kSecAttrService as String: self.service,
|
|
110
|
-
kSecAttrAccount as String: self.account,
|
|
111
|
-
]
|
|
112
|
-
if dataProtection {
|
|
113
|
-
q[kSecUseDataProtectionKeychain as String] = true
|
|
114
|
-
}
|
|
115
|
-
return q
|
|
116
|
-
}
|
|
117
|
-
}
|