diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 51d4dcd85d..cddba022d8 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -1245,6 +1245,7 @@ "normalize-line-endings_0.3.0": "{\"dependencies\":[],\"features\":{}}", "notify-types_2.1.0": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1.34.0\"},{\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.26.0\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.89\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.39\"},{\"name\":\"web-time\",\"optional\":true,\"req\":\"^1.1.0\"}],\"features\":{\"serde\":[\"dep:serde\",\"bitflags/serde\"],\"serialization-compat-6\":[]}}", "notify_8.2.0": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2.7.0\",\"target\":\"cfg(target_os=\\\"macos\\\")\"},{\"name\":\"crossbeam-channel\",\"optional\":true,\"req\":\"^0.5.0\"},{\"name\":\"flume\",\"optional\":true,\"req\":\"^0.11.1\"},{\"name\":\"fsevent-sys\",\"optional\":true,\"req\":\"^4.0.0\",\"target\":\"cfg(target_os=\\\"macos\\\")\"},{\"default_features\":false,\"name\":\"inotify\",\"req\":\"^0.11.0\",\"target\":\"cfg(any(target_os=\\\"linux\\\", target_os=\\\"android\\\"))\"},{\"kind\":\"dev\",\"name\":\"insta\",\"req\":\"^1.34.0\"},{\"name\":\"kqueue\",\"req\":\"^1.1.1\",\"target\":\"cfg(any(target_os=\\\"freebsd\\\", target_os=\\\"openbsd\\\", target_os = \\\"netbsd\\\", target_os = \\\"dragonflybsd\\\", target_os = \\\"ios\\\"))\"},{\"name\":\"kqueue\",\"optional\":true,\"req\":\"^1.1.1\",\"target\":\"cfg(target_os=\\\"macos\\\")\"},{\"name\":\"libc\",\"req\":\"^0.2.4\"},{\"name\":\"log\",\"req\":\"^0.4.17\"},{\"features\":[\"os-ext\"],\"name\":\"mio\",\"req\":\"^1.0\",\"target\":\"cfg(any(target_os=\\\"freebsd\\\", target_os=\\\"openbsd\\\", target_os = \\\"netbsd\\\", target_os = \\\"dragonflybsd\\\", target_os = \\\"ios\\\"))\"},{\"features\":[\"os-ext\"],\"name\":\"mio\",\"req\":\"^1.0\",\"target\":\"cfg(any(target_os=\\\"linux\\\", target_os=\\\"android\\\"))\"},{\"features\":[\"os-ext\"],\"name\":\"mio\",\"optional\":true,\"req\":\"^1.0\",\"target\":\"cfg(target_os=\\\"macos\\\")\"},{\"kind\":\"dev\",\"name\":\"nix\",\"req\":\"^0.29.0\"},{\"name\":\"notify-types\",\"req\":\"^2.0.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.39\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.10.0\"},{\"kind\":\"dev\",\"name\":\"trash\",\"req\":\"^5.2.2\",\"target\":\"cfg(target_os = \\\"windows\\\")\"},{\"name\":\"walkdir\",\"req\":\"^2.4.0\"},{\"features\":[\"Win32_System_Threading\",\"Win32_Foundation\",\"Win32_Storage_FileSystem\",\"Win32_Security\",\"Win32_System_WindowsProgramming\",\"Win32_System_IO\"],\"name\":\"windows-sys\",\"req\":\"^0.60.1\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[\"macos_fsevent\"],\"macos_fsevent\":[\"fsevent-sys\"],\"macos_kqueue\":[\"kqueue\",\"mio\"],\"serde\":[\"notify-types/serde\"],\"serialization-compat-6\":[\"notify-types/serialization-compat-6\"]}}", + "ntapi_0.4.3": "{\"dependencies\":[{\"features\":[\"cfg\",\"evntrace\",\"in6addr\",\"inaddr\",\"minwinbase\",\"ntsecapi\",\"windef\",\"winioctl\"],\"name\":\"winapi\",\"req\":\"^0.3.9\"}],\"features\":{\"default\":[\"user\"],\"func-types\":[],\"impl-default\":[\"winapi/impl-default\"],\"kernel\":[],\"user\":[]}}", "nu-ansi-term_0.50.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3.3\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.152\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.94\"},{\"features\":[\"Win32_Foundation\",\"Win32_System_Console\",\"Win32_Storage_FileSystem\",\"Win32_Security\"],\"name\":\"windows\",\"package\":\"windows-sys\",\"req\":\">=0.59, <=0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[\"std\"],\"derive_serde_style\":[\"serde\"],\"gnu_legacy\":[],\"std\":[]}}", "num-bigint_0.4.6": "{\"dependencies\":[{\"default_features\":false,\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"i128\"],\"name\":\"num-integer\",\"req\":\"^0.1.46\"},{\"default_features\":false,\"features\":[\"i128\"],\"name\":\"num-traits\",\"req\":\"^0.2.18\"},{\"default_features\":false,\"name\":\"quickcheck\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"name\":\"rand\",\"optional\":true,\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"}],\"features\":{\"arbitrary\":[\"dep:arbitrary\"],\"default\":[\"std\"],\"quickcheck\":[\"dep:quickcheck\"],\"rand\":[\"dep:rand\"],\"serde\":[\"dep:serde\"],\"std\":[\"num-integer/std\",\"num-traits/std\"]}}", "num-complex_0.4.6": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bytecheck\",\"optional\":true,\"req\":\"^0.6\"},{\"name\":\"bytemuck\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"i128\"],\"name\":\"num-traits\",\"req\":\"^0.2.18\"},{\"default_features\":false,\"name\":\"rand\",\"optional\":true,\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"rkyv\",\"optional\":true,\"req\":\"^0.7\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"}],\"features\":{\"bytecheck\":[\"dep:bytecheck\"],\"bytemuck\":[\"dep:bytemuck\"],\"default\":[\"std\"],\"libm\":[\"num-traits/libm\"],\"rand\":[\"dep:rand\"],\"rkyv\":[\"dep:rkyv\"],\"serde\":[\"dep:serde\"],\"std\":[\"num-traits/std\"]}}", @@ -1267,7 +1268,9 @@ "objc2-core-text_0.3.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bitflags\",\"optional\":true,\"req\":\"^2.5.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"block2\",\"optional\":true,\"req\":\">=0.6.1, <0.8.0\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.80\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"objc2\",\"optional\":true,\"req\":\">=0.6.2, <0.8.0\"},{\"default_features\":false,\"name\":\"objc2-core-foundation\",\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"CGContext\",\"CGFont\",\"CGImage\",\"CGPath\"],\"name\":\"objc2-core-graphics\",\"optional\":true,\"req\":\"^0.3.2\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"}],\"features\":{\"CTDefines\":[],\"CTFont\":[\"bitflags\",\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFCGTypes\",\"objc2-core-foundation/CFCharacterSet\",\"objc2-core-foundation/CFData\",\"objc2-core-foundation/CFDictionary\",\"objc2-core-foundation/CFString\"],\"CTFontCollection\":[\"bitflags\",\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFDictionary\",\"objc2-core-foundation/CFSet\"],\"CTFontDescriptor\":[\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFCGTypes\",\"objc2-core-foundation/CFDictionary\",\"objc2-core-foundation/CFNumber\",\"objc2-core-foundation/CFSet\"],\"CTFontManager\":[\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFBundle\",\"objc2-core-foundation/CFData\",\"objc2-core-foundation/CFDictionary\",\"objc2-core-foundation/CFError\",\"objc2-core-foundation/CFRunLoop\",\"objc2-core-foundation/CFURL\"],\"CTFontManagerErrors\":[],\"CTFontTraits\":[\"bitflags\"],\"CTFrame\":[\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFCGTypes\",\"objc2-core-foundation/CFDictionary\"],\"CTFramesetter\":[\"objc2-core-foundation/CFAttributedString\",\"objc2-core-foundation/CFCGTypes\",\"objc2-core-foundation/CFDictionary\"],\"CTGlyphInfo\":[],\"CTLine\":[\"bitflags\",\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFAttributedString\",\"objc2-core-foundation/CFCGTypes\"],\"CTParagraphStyle\":[],\"CTRubyAnnotation\":[\"objc2-core-foundation/CFCGTypes\",\"objc2-core-foundation/CFDictionary\"],\"CTRun\":[\"bitflags\",\"objc2-core-foundation/CFCGTypes\",\"objc2-core-foundation/CFDictionary\"],\"CTRunDelegate\":[\"objc2-core-foundation/CFCGTypes\"],\"CTStringAttributes\":[\"bitflags\"],\"CTTextTab\":[\"objc2-core-foundation/CFDictionary\"],\"CTTypesetter\":[\"objc2-core-foundation/CFAttributedString\",\"objc2-core-foundation/CFDictionary\"],\"SFNTLayoutTypes\":[],\"SFNTTypes\":[],\"alloc\":[],\"bitflags\":[\"dep:bitflags\"],\"block2\":[\"dep:block2\"],\"default\":[\"std\",\"CTDefines\",\"CTFont\",\"CTFontCollection\",\"CTFontDescriptor\",\"CTFontManager\",\"CTFontManagerErrors\",\"CTFontTraits\",\"CTFrame\",\"CTFramesetter\",\"CTGlyphInfo\",\"CTLine\",\"CTParagraphStyle\",\"CTRubyAnnotation\",\"CTRun\",\"CTRunDelegate\",\"CTStringAttributes\",\"CTTextTab\",\"CTTypesetter\",\"SFNTLayoutTypes\",\"SFNTTypes\",\"bitflags\",\"block2\",\"libc\",\"objc2\",\"objc2-core-graphics\"],\"libc\":[\"dep:libc\"],\"objc2\":[\"dep:objc2\",\"objc2-core-foundation/objc2\",\"objc2-core-graphics?/objc2\"],\"objc2-core-graphics\":[\"dep:objc2-core-graphics\"],\"std\":[\"alloc\"],\"unstable-darwin-objc\":[]}}", "objc2-encode_4.1.0": "{\"dependencies\":[],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[\"alloc\"]}}", "objc2-foundation_0.3.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bitflags\",\"optional\":true,\"req\":\"^2.5.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"block2\",\"optional\":true,\"req\":\">=0.6.1, <0.8.0\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.80\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"objc2\",\"req\":\">=0.6.2, <0.8.0\"},{\"default_features\":false,\"features\":[\"CFArray\",\"CFAttributedString\",\"CFCGTypes\",\"CFCalendar\",\"CFCharacterSet\",\"CFData\",\"CFDate\",\"CFDictionary\",\"CFError\",\"CFFileSecurity\",\"CFLocale\",\"CFMachPort\",\"CFMessagePort\",\"CFRunLoop\",\"CFSet\",\"CFStream\",\"CFURL\",\"objc2\"],\"name\":\"objc2-core-foundation\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"CFString\"],\"kind\":\"dev\",\"name\":\"objc2-core-foundation\",\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"AE\",\"AEDataModel\",\"objc2\"],\"name\":\"objc2-core-services\",\"optional\":true,\"req\":\"^0.3.2\",\"target\":\"cfg(target_vendor = \\\"apple\\\")\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1.0\"}],\"features\":{\"FoundationErrors\":[],\"FoundationLegacySwiftCompatibility\":[],\"NSAffineTransform\":[],\"NSAppleEventDescriptor\":[\"bitflags\"],\"NSAppleEventManager\":[],\"NSAppleScript\":[],\"NSArchiver\":[],\"NSArray\":[\"bitflags\"],\"NSAttributedString\":[\"bitflags\"],\"NSAutoreleasePool\":[],\"NSBackgroundActivityScheduler\":[],\"NSBundle\":[],\"NSByteCountFormatter\":[\"bitflags\"],\"NSByteOrder\":[],\"NSCache\":[],\"NSCalendar\":[\"bitflags\"],\"NSCalendarDate\":[],\"NSCharacterSet\":[],\"NSClassDescription\":[],\"NSCoder\":[],\"NSComparisonPredicate\":[\"bitflags\"],\"NSCompoundPredicate\":[],\"NSConnection\":[],\"NSData\":[\"bitflags\"],\"NSDate\":[],\"NSDateComponentsFormatter\":[\"bitflags\"],\"NSDateFormatter\":[],\"NSDateInterval\":[],\"NSDateIntervalFormatter\":[],\"NSDebug\":[],\"NSDecimal\":[],\"NSDecimalNumber\":[],\"NSDictionary\":[],\"NSDistantObject\":[],\"NSDistributedLock\":[],\"NSDistributedNotificationCenter\":[\"bitflags\"],\"NSEnergyFormatter\":[],\"NSEnumerator\":[],\"NSError\":[],\"NSException\":[],\"NSExpression\":[],\"NSExtensionContext\":[],\"NSExtensionItem\":[],\"NSExtensionRequestHandling\":[],\"NSFileCoordinator\":[\"bitflags\"],\"NSFileHandle\":[],\"NSFileManager\":[\"bitflags\"],\"NSFilePresenter\":[],\"NSFileVersion\":[\"bitflags\"],\"NSFileWrapper\":[\"bitflags\"],\"NSFormatter\":[],\"NSGarbageCollector\":[],\"NSGeometry\":[\"bitflags\"],\"NSHFSFileTypes\":[],\"NSHTTPCookie\":[],\"NSHTTPCookieStorage\":[],\"NSHashTable\":[],\"NSHost\":[],\"NSISO8601DateFormatter\":[\"bitflags\"],\"NSIndexPath\":[],\"NSIndexSet\":[],\"NSInflectionRule\":[],\"NSInvocation\":[],\"NSItemProvider\":[\"bitflags\"],\"NSJSONSerialization\":[\"bitflags\"],\"NSKeyValueCoding\":[],\"NSKeyValueObserving\":[\"bitflags\"],\"NSKeyValueSharedObservers\":[],\"NSKeyedArchiver\":[],\"NSLengthFormatter\":[],\"NSLinguisticTagger\":[\"bitflags\"],\"NSListFormatter\":[],\"NSLocale\":[],\"NSLocalizedNumberFormatRule\":[],\"NSLock\":[],\"NSMapTable\":[],\"NSMassFormatter\":[],\"NSMeasurement\":[\"NSUnit\"],\"NSMeasurementFormatter\":[\"bitflags\"],\"NSMetadata\":[],\"NSMetadataAttributes\":[],\"NSMethodSignature\":[],\"NSMorphology\":[],\"NSNetServices\":[\"bitflags\"],\"NSNotification\":[],\"NSNotificationQueue\":[\"bitflags\"],\"NSNull\":[],\"NSNumberFormatter\":[],\"NSObjCRuntime\":[\"bitflags\"],\"NSObject\":[],\"NSObjectScripting\":[],\"NSOperation\":[],\"NSOrderedCollectionChange\":[],\"NSOrderedCollectionDifference\":[\"bitflags\"],\"NSOrderedSet\":[],\"NSOrthography\":[],\"NSPathUtilities\":[\"bitflags\"],\"NSPersonNameComponents\":[],\"NSPersonNameComponentsFormatter\":[\"bitflags\"],\"NSPointerArray\":[],\"NSPointerFunctions\":[\"bitflags\"],\"NSPort\":[\"bitflags\"],\"NSPortCoder\":[],\"NSPortMessage\":[],\"NSPortNameServer\":[],\"NSPredicate\":[],\"NSProcessInfo\":[\"bitflags\"],\"NSProgress\":[],\"NSPropertyList\":[\"bitflags\"],\"NSProtocolChecker\":[],\"NSProxy\":[],\"NSRange\":[],\"NSRegularExpression\":[\"bitflags\"],\"NSRelativeDateTimeFormatter\":[],\"NSRunLoop\":[],\"NSScanner\":[],\"NSScriptClassDescription\":[],\"NSScriptCoercionHandler\":[],\"NSScriptCommand\":[],\"NSScriptCommandDescription\":[],\"NSScriptExecutionContext\":[],\"NSScriptKeyValueCoding\":[],\"NSScriptObjectSpecifiers\":[],\"NSScriptStandardSuiteCommands\":[],\"NSScriptSuiteRegistry\":[],\"NSScriptWhoseTests\":[],\"NSSet\":[],\"NSSortDescriptor\":[],\"NSSpellServer\":[],\"NSStream\":[\"bitflags\"],\"NSString\":[\"bitflags\"],\"NSTask\":[],\"NSTermOfAddress\":[],\"NSTextCheckingResult\":[\"bitflags\"],\"NSThread\":[],\"NSTimeZone\":[],\"NSTimer\":[],\"NSURL\":[\"bitflags\"],\"NSURLAuthenticationChallenge\":[],\"NSURLCache\":[],\"NSURLConnection\":[],\"NSURLCredential\":[],\"NSURLCredentialStorage\":[],\"NSURLDownload\":[],\"NSURLError\":[],\"NSURLHandle\":[],\"NSURLProtectionSpace\":[],\"NSURLProtocol\":[],\"NSURLRequest\":[],\"NSURLResponse\":[],\"NSURLSession\":[],\"NSUUID\":[],\"NSUbiquitousKeyValueStore\":[],\"NSUndoManager\":[],\"NSUnit\":[],\"NSUserActivity\":[],\"NSUserDefaults\":[],\"NSUserNotification\":[],\"NSUserScriptTask\":[],\"NSValue\":[],\"NSValueTransformer\":[],\"NSXMLDTD\":[],\"NSXMLDTDNode\":[],\"NSXMLDocument\":[],\"NSXMLElement\":[],\"NSXMLNode\":[],\"NSXMLNodeOptions\":[\"bitflags\"],\"NSXMLParser\":[],\"NSXPCConnection\":[\"bitflags\"],\"NSZone\":[],\"alloc\":[],\"bitflags\":[\"dep:bitflags\"],\"block2\":[\"dep:block2\"],\"default\":[\"std\",\"FoundationErrors\",\"FoundationLegacySwiftCompatibility\",\"NSAffineTransform\",\"NSAppleEventDescriptor\",\"NSAppleEventManager\",\"NSAppleScript\",\"NSArchiver\",\"NSArray\",\"NSAttributedString\",\"NSAutoreleasePool\",\"NSBackgroundActivityScheduler\",\"NSBundle\",\"NSByteCountFormatter\",\"NSByteOrder\",\"NSCache\",\"NSCalendar\",\"NSCalendarDate\",\"NSCharacterSet\",\"NSClassDescription\",\"NSCoder\",\"NSComparisonPredicate\",\"NSCompoundPredicate\",\"NSConnection\",\"NSData\",\"NSDate\",\"NSDateComponentsFormatter\",\"NSDateFormatter\",\"NSDateInterval\",\"NSDateIntervalFormatter\",\"NSDebug\",\"NSDecimal\",\"NSDecimalNumber\",\"NSDictionary\",\"NSDistantObject\",\"NSDistributedLock\",\"NSDistributedNotificationCenter\",\"NSEnergyFormatter\",\"NSEnumerator\",\"NSError\",\"NSException\",\"NSExpression\",\"NSExtensionContext\",\"NSExtensionItem\",\"NSExtensionRequestHandling\",\"NSFileCoordinator\",\"NSFileHandle\",\"NSFileManager\",\"NSFilePresenter\",\"NSFileVersion\",\"NSFileWrapper\",\"NSFormatter\",\"NSGarbageCollector\",\"NSGeometry\",\"NSHFSFileTypes\",\"NSHTTPCookie\",\"NSHTTPCookieStorage\",\"NSHashTable\",\"NSHost\",\"NSISO8601DateFormatter\",\"NSIndexPath\",\"NSIndexSet\",\"NSInflectionRule\",\"NSInvocation\",\"NSItemProvider\",\"NSJSONSerialization\",\"NSKeyValueCoding\",\"NSKeyValueObserving\",\"NSKeyValueSharedObservers\",\"NSKeyedArchiver\",\"NSLengthFormatter\",\"NSLinguisticTagger\",\"NSListFormatter\",\"NSLocale\",\"NSLocalizedNumberFormatRule\",\"NSLock\",\"NSMapTable\",\"NSMassFormatter\",\"NSMeasurement\",\"NSMeasurementFormatter\",\"NSMetadata\",\"NSMetadataAttributes\",\"NSMethodSignature\",\"NSMorphology\",\"NSNetServices\",\"NSNotification\",\"NSNotificationQueue\",\"NSNull\",\"NSNumberFormatter\",\"NSObjCRuntime\",\"NSObject\",\"NSObjectScripting\",\"NSOperation\",\"NSOrderedCollectionChange\",\"NSOrderedCollectionDifference\",\"NSOrderedSet\",\"NSOrthography\",\"NSPathUtilities\",\"NSPersonNameComponents\",\"NSPersonNameComponentsFormatter\",\"NSPointerArray\",\"NSPointerFunctions\",\"NSPort\",\"NSPortCoder\",\"NSPortMessage\",\"NSPortNameServer\",\"NSPredicate\",\"NSProcessInfo\",\"NSProgress\",\"NSPropertyList\",\"NSProtocolChecker\",\"NSProxy\",\"NSRange\",\"NSRegularExpression\",\"NSRelativeDateTimeFormatter\",\"NSRunLoop\",\"NSScanner\",\"NSScriptClassDescription\",\"NSScriptCoercionHandler\",\"NSScriptCommand\",\"NSScriptCommandDescription\",\"NSScriptExecutionContext\",\"NSScriptKeyValueCoding\",\"NSScriptObjectSpecifiers\",\"NSScriptStandardSuiteCommands\",\"NSScriptSuiteRegistry\",\"NSScriptWhoseTests\",\"NSSet\",\"NSSortDescriptor\",\"NSSpellServer\",\"NSStream\",\"NSString\",\"NSTask\",\"NSTermOfAddress\",\"NSTextCheckingResult\",\"NSThread\",\"NSTimeZone\",\"NSTimer\",\"NSURL\",\"NSURLAuthenticationChallenge\",\"NSURLCache\",\"NSURLConnection\",\"NSURLCredential\",\"NSURLCredentialStorage\",\"NSURLDownload\",\"NSURLError\",\"NSURLHandle\",\"NSURLProtectionSpace\",\"NSURLProtocol\",\"NSURLRequest\",\"NSURLResponse\",\"NSURLSession\",\"NSUUID\",\"NSUbiquitousKeyValueStore\",\"NSUndoManager\",\"NSUnit\",\"NSUserActivity\",\"NSUserDefaults\",\"NSUserNotification\",\"NSUserScriptTask\",\"NSValue\",\"NSValueTransformer\",\"NSXMLDTD\",\"NSXMLDTDNode\",\"NSXMLDocument\",\"NSXMLElement\",\"NSXMLNode\",\"NSXMLNodeOptions\",\"NSXMLParser\",\"NSXPCConnection\",\"NSZone\",\"bitflags\",\"block2\",\"libc\",\"objc2-core-foundation\"],\"gnustep-1-7\":[\"objc2/gnustep-1-7\",\"block2?/gnustep-1-7\"],\"gnustep-1-8\":[\"gnustep-1-7\",\"objc2/gnustep-1-8\",\"block2?/gnustep-1-8\"],\"gnustep-1-9\":[\"gnustep-1-8\",\"objc2/gnustep-1-9\",\"block2?/gnustep-1-9\"],\"gnustep-2-0\":[\"gnustep-1-9\",\"objc2/gnustep-2-0\",\"block2?/gnustep-2-0\"],\"gnustep-2-1\":[\"gnustep-2-0\",\"objc2/gnustep-2-1\",\"block2?/gnustep-2-1\"],\"libc\":[\"dep:libc\"],\"objc2-core-foundation\":[\"dep:objc2-core-foundation\"],\"objc2-core-services\":[\"dep:objc2-core-services\"],\"std\":[\"alloc\"],\"unstable-darwin-objc\":[],\"unstable-mutation-return-null\":[\"NSNull\"],\"unstable-static-nsstring\":[]}}", + "objc2-io-kit_0.3.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bitflags\",\"optional\":true,\"req\":\"^2.5.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"block2\",\"optional\":true,\"req\":\">=0.6.1, <0.8.0\"},{\"default_features\":false,\"features\":[\"alloc\",\"block2\"],\"name\":\"dispatch2\",\"optional\":true,\"req\":\">=0.3.0, <0.5.0\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.80\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"objc2\",\"optional\":true,\"req\":\">=0.6.2, <0.8.0\"},{\"default_features\":false,\"features\":[\"CFArray\",\"CFData\",\"CFDictionary\",\"CFPlugInCOM\",\"CFRunLoop\",\"CFURL\",\"CFUUID\"],\"name\":\"objc2-core-foundation\",\"req\":\"^0.3.2\"}],\"features\":{\"AppleUSBDefinitions\":[],\"IOUSBHostFamilyDefinitions\":[],\"IOUSBLib\":[\"objc2-core-foundation/CFPlugInCOM\",\"objc2-core-foundation/CFRunLoop\",\"objc2-core-foundation/CFUUID\"],\"USB\":[],\"USBSpec\":[],\"alloc\":[],\"bitflags\":[\"dep:bitflags\"],\"block2\":[\"dep:block2\"],\"default\":[\"std\",\"AppleUSBDefinitions\",\"IOUSBHostFamilyDefinitions\",\"IOUSBLib\",\"USB\",\"USBSpec\",\"bitflags\",\"block2\",\"dispatch2\",\"graphics\",\"hid\",\"hidsystem\",\"libc\",\"network\",\"objc2\",\"ps\",\"pwr_mgt\",\"serial\",\"usb\"],\"dispatch2\":[\"dep:dispatch2\"],\"graphics\":[\"objc2-core-foundation/CFDictionary\",\"objc2-core-foundation/CFPlugInCOM\",\"objc2-core-foundation/CFUUID\"],\"hid\":[\"bitflags\",\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFDate\",\"objc2-core-foundation/CFDictionary\",\"objc2-core-foundation/CFPlugInCOM\",\"objc2-core-foundation/CFRunLoop\",\"objc2-core-foundation/CFSet\",\"objc2-core-foundation/CFUUID\"],\"hidsystem\":[\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFDictionary\"],\"libc\":[\"dep:libc\"],\"network\":[],\"objc2\":[\"dep:objc2\",\"dispatch2?/objc2\",\"objc2-core-foundation/objc2\"],\"ps\":[\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFDate\",\"objc2-core-foundation/CFDictionary\",\"objc2-core-foundation/CFPlugInCOM\",\"objc2-core-foundation/CFRunLoop\",\"objc2-core-foundation/CFSet\",\"objc2-core-foundation/CFUUID\"],\"pwr_mgt\":[\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFDate\",\"objc2-core-foundation/CFDictionary\"],\"serial\":[],\"std\":[\"alloc\"],\"unstable-darwin-objc\":[],\"usb\":[]}}", "objc2-io-surface_0.3.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bitflags\",\"optional\":true,\"req\":\"^2.5.0\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.80\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"objc2\",\"optional\":true,\"req\":\">=0.6.2, <0.8.0\"},{\"default_features\":false,\"features\":[\"CFDictionary\"],\"name\":\"objc2-core-foundation\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"NSDictionary\",\"NSObject\",\"NSString\",\"alloc\"],\"name\":\"objc2-foundation\",\"optional\":true,\"req\":\"^0.3.2\"}],\"features\":{\"IOSurface\":[],\"IOSurfaceAPI\":[],\"IOSurfaceBase\":[],\"IOSurfaceRef\":[\"bitflags\"],\"IOSurfaceTypes\":[\"bitflags\"],\"ObjC\":[\"objc2\"],\"alloc\":[],\"bitflags\":[\"dep:bitflags\"],\"default\":[\"std\",\"IOSurface\",\"IOSurfaceAPI\",\"IOSurfaceBase\",\"IOSurfaceRef\",\"IOSurfaceTypes\",\"bitflags\",\"libc\",\"objc2\",\"objc2-core-foundation\",\"objc2-foundation\"],\"libc\":[\"dep:libc\"],\"objc2\":[\"dep:objc2\",\"objc2-core-foundation?/objc2\"],\"objc2-core-foundation\":[\"dep:objc2-core-foundation\"],\"objc2-foundation\":[\"dep:objc2-foundation\"],\"std\":[\"alloc\"],\"unstable-darwin-objc\":[]}}", + "objc2-open-directory_0.3.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"alloc\",\"objc2\"],\"name\":\"dispatch2\",\"optional\":true,\"req\":\">=0.3.0, <0.5.0\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"objc2\",\"req\":\">=0.6.2, <0.8.0\"},{\"default_features\":false,\"features\":[\"CFArray\",\"CFData\",\"CFDictionary\",\"CFError\",\"CFRunLoop\",\"objc2\"],\"name\":\"objc2-core-foundation\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"NSString\",\"alloc\"],\"name\":\"objc2-foundation\",\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"SFAuthorization\"],\"name\":\"objc2-security-foundation\",\"optional\":true,\"req\":\"^0.3.2\"}],\"features\":{\"CFODContext\":[],\"CFODNode\":[\"objc2-foundation/NSString\"],\"CFODQuery\":[\"objc2-foundation/NSString\"],\"CFODRecord\":[\"objc2-foundation/NSString\"],\"CFODSession\":[],\"CFOpenDirectory\":[],\"CFOpenDirectoryConstants\":[\"objc2-foundation/NSString\"],\"ODAttributeMap\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"ODConfiguration\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSError\",\"objc2-foundation/NSString\"],\"ODMappings\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"ODModuleEntry\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"ODNode\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSData\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSString\"],\"ODQuery\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSError\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSOperation\",\"objc2-foundation/NSRunLoop\",\"objc2-foundation/NSString\"],\"ODRecord\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSString\"],\"ODRecordMap\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSString\"],\"ODSession\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSString\"],\"alloc\":[],\"default\":[\"std\",\"CFODContext\",\"CFODNode\",\"CFODQuery\",\"CFODRecord\",\"CFODSession\",\"CFOpenDirectory\",\"CFOpenDirectoryConstants\",\"ODAttributeMap\",\"ODConfiguration\",\"ODMappings\",\"ODModuleEntry\",\"ODNode\",\"ODQuery\",\"ODRecord\",\"ODRecordMap\",\"ODSession\",\"dispatch2\",\"objc2-core-foundation\",\"objc2-security-foundation\"],\"dispatch2\":[\"dep:dispatch2\"],\"objc2-core-foundation\":[\"dep:objc2-core-foundation\"],\"objc2-security-foundation\":[\"dep:objc2-security-foundation\"],\"std\":[\"alloc\"],\"unstable-darwin-objc\":[]}}", "objc2-quartz-core_0.3.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bitflags\",\"optional\":true,\"req\":\"^2.5.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"block2\",\"optional\":true,\"req\":\">=0.6.1, <0.8.0\"},{\"default_features\":false,\"name\":\"libc\",\"optional\":true,\"req\":\"^0.2.80\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"objc2\",\"req\":\">=0.6.2, <0.8.0\"},{\"default_features\":false,\"features\":[\"CFCGTypes\",\"CFDate\",\"objc2\"],\"name\":\"objc2-core-foundation\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"CGColor\",\"CGColorSpace\",\"CGContext\",\"CGPath\",\"objc2\"],\"name\":\"objc2-core-graphics\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"CVBase\",\"objc2\"],\"name\":\"objc2-core-video\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"objc2-foundation\",\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"MTLAllocation\",\"MTLDevice\",\"MTLDrawable\",\"MTLPixelFormat\",\"MTLResidencySet\",\"MTLResource\",\"MTLTexture\"],\"name\":\"objc2-metal\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"CGLTypes\"],\"name\":\"objc2-open-gl\",\"optional\":true,\"req\":\"^0.3.2\",\"target\":\"cfg(target_os = \\\"macos\\\")\"}],\"features\":{\"CAAnimation\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"CABase\":[],\"CAConstraintLayoutManager\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"CADisplayLink\":[\"objc2-foundation/NSObjCRuntime\",\"objc2-foundation/NSRunLoop\",\"objc2-foundation/NSString\"],\"CAEAGLLayer\":[],\"CAEDRMetadata\":[\"objc2-foundation/NSData\",\"objc2-foundation/NSObject\"],\"CAEmitterCell\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"CAEmitterLayer\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"CAFrameRateRange\":[],\"CAGradientLayer\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"CALayer\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSNull\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"CAMediaTiming\":[\"objc2-foundation/NSString\"],\"CAMediaTimingFunction\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"CAMetalDisplayLink\":[\"objc2-foundation/NSObjCRuntime\",\"objc2-foundation/NSRunLoop\",\"objc2-foundation/NSString\"],\"CAMetalLayer\":[\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\"],\"CAOpenGLLayer\":[\"objc2-foundation/NSObject\"],\"CARemoteLayerClient\":[],\"CARemoteLayerServer\":[],\"CARenderer\":[\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSString\"],\"CAReplicatorLayer\":[\"objc2-foundation/NSObject\"],\"CAScrollLayer\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"CAShapeLayer\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"CATextLayer\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"CATiledLayer\":[\"objc2-foundation/NSObject\"],\"CATransaction\":[\"objc2-foundation/NSString\"],\"CATransform3D\":[\"objc2-foundation/NSValue\"],\"CATransformLayer\":[\"objc2-foundation/NSObject\"],\"CAValueFunction\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"CoreAnimation\":[],\"alloc\":[],\"bitflags\":[\"dep:bitflags\"],\"block2\":[\"dep:block2\"],\"default\":[\"std\",\"CAAnimation\",\"CABase\",\"CAConstraintLayoutManager\",\"CADisplayLink\",\"CAEAGLLayer\",\"CAEDRMetadata\",\"CAEmitterCell\",\"CAEmitterLayer\",\"CAFrameRateRange\",\"CAGradientLayer\",\"CALayer\",\"CAMediaTiming\",\"CAMediaTimingFunction\",\"CAMetalDisplayLink\",\"CAMetalLayer\",\"CAOpenGLLayer\",\"CARemoteLayerClient\",\"CARemoteLayerServer\",\"CARenderer\",\"CAReplicatorLayer\",\"CAScrollLayer\",\"CAShapeLayer\",\"CATextLayer\",\"CATiledLayer\",\"CATransaction\",\"CATransform3D\",\"CATransformLayer\",\"CAValueFunction\",\"CoreAnimation\",\"bitflags\",\"block2\",\"libc\",\"objc2-core-foundation\",\"objc2-core-graphics\",\"objc2-core-video\",\"objc2-metal\"],\"gnustep-1-7\":[],\"gnustep-1-8\":[],\"gnustep-1-9\":[],\"gnustep-2-0\":[],\"gnustep-2-1\":[],\"libc\":[\"dep:libc\"],\"objc2-core-foundation\":[\"dep:objc2-core-foundation\"],\"objc2-core-graphics\":[\"dep:objc2-core-graphics\"],\"objc2-core-video\":[\"dep:objc2-core-video\"],\"objc2-metal\":[\"dep:objc2-metal\"],\"objc2-open-gl\":[\"dep:objc2-open-gl\"],\"std\":[\"alloc\"],\"unstable-darwin-objc\":[]}}", "objc2-ui-kit_0.3.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bitflags\",\"optional\":true,\"req\":\"^2.5.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"block2\",\"optional\":true,\"req\":\">=0.6.1, <0.8.0\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"objc2\",\"req\":\">=0.6.2, <0.8.0\"},{\"default_features\":false,\"features\":[\"CKContainer\",\"CKRecord\",\"CKShare\",\"CKShareMetadata\"],\"name\":\"objc2-cloud-kit\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"NSManagedObjectContext\",\"NSManagedObjectModel\"],\"name\":\"objc2-core-data\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"CFCGTypes\",\"CFDate\",\"objc2\"],\"name\":\"objc2-core-foundation\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"CGColor\",\"CGContext\",\"CGFont\",\"CGImage\",\"CGPath\",\"objc2\"],\"name\":\"objc2-core-graphics\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"CIColor\",\"CIImage\"],\"name\":\"objc2-core-image\",\"optional\":true,\"req\":\"^0.3.2\",\"target\":\"cfg(not(target_os = \\\"watchos\\\"))\"},{\"default_features\":false,\"features\":[\"CLRegion\"],\"name\":\"objc2-core-location\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"CTFont\",\"CTFontDescriptor\",\"objc2\"],\"name\":\"objc2-core-text\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"objc2-foundation\",\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"CADisplayLink\",\"CAFrameRateRange\",\"CALayer\",\"CAMediaTiming\",\"CATransform3D\",\"objc2-core-foundation\"],\"name\":\"objc2-quartz-core\",\"optional\":true,\"req\":\"^0.3.2\",\"target\":\"cfg(not(target_os = \\\"watchos\\\"))\"},{\"default_features\":false,\"features\":[\"NSSymbolEffect\"],\"name\":\"objc2-symbols\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"UTType\"],\"name\":\"objc2-uniform-type-identifiers\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"UNNotificationResponse\"],\"name\":\"objc2-user-notifications\",\"optional\":true,\"req\":\"^0.3.2\"}],\"features\":{\"DocumentManager\":[],\"NSAdaptiveImageGlyph\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSData\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"NSAttributedString\":[\"bitflags\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSData\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSFileWrapper\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"NSDataAsset\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSData\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"NSDiffableDataSourceSectionSnapshot\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"NSFileProviderExtension\":[],\"NSIndexPath_UIKitAdditions\":[\"objc2-foundation/NSIndexPath\"],\"NSItemProvider_UIKitAdditions\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSData\",\"objc2-foundation/NSError\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSString\"],\"NSLayoutAnchor\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"NSLayoutConstraint\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSString\"],\"NSLayoutManager\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\"],\"NSParagraphStyle\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCharacterSet\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSLocale\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"NSShadow\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"NSStringDrawing\":[\"bitflags\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSString\"],\"NSText\":[],\"NSTextAttachment\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSData\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSFileWrapper\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"NSTextContainer\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"NSTextContentManager\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSError\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\"],\"NSTextElement\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\"],\"NSTextLayoutFragment\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSOperation\"],\"NSTextLayoutManager\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSOperation\",\"objc2-foundation/NSString\"],\"NSTextLineFragment\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\"],\"NSTextList\":[\"bitflags\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"NSTextListElement\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSString\"],\"NSTextRange\":[\"objc2-foundation/NSObjCRuntime\"],\"NSTextSelection\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"NSTextSelectionNavigation\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"NSTextStorage\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\"],\"NSTextViewportLayoutController\":[],\"NSToolbar_UIKitAdditions\":[],\"NSTouchBar_UIKitAdditions\":[],\"NSUserActivity_NSItemProvider\":[],\"PrintKitUI\":[],\"ShareSheet\":[],\"UIAccelerometer\":[\"objc2-foundation/NSDate\"],\"UIAccessibility\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UIAccessibilityAdditions\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSString\"],\"UIAccessibilityConstants\":[\"bitflags\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSString\"],\"UIAccessibilityContainer\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSRange\"],\"UIAccessibilityContentSizeCategoryImageAdjusting\":[],\"UIAccessibilityCustomAction\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSString\"],\"UIAccessibilityCustomRotor\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSString\"],\"UIAccessibilityElement\":[\"objc2-foundation/NSString\"],\"UIAccessibilityIdentification\":[\"objc2-foundation/NSString\"],\"UIAccessibilityLocationDescriptor\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSString\"],\"UIAccessibilityZoom\":[],\"UIAction\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIActionSheet\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIActivity\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"UIActivityCollaborationModeRestriction\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIActivityIndicatorView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIActivityItemProvider\":[\"objc2-foundation/NSOperation\",\"objc2-foundation/NSString\"],\"UIActivityItemsConfiguration\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSString\"],\"UIActivityItemsConfigurationReading\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSString\"],\"UIActivityItemsConfigurationReading_ShareSheet\":[\"objc2-foundation/NSString\"],\"UIActivityViewController\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSError\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIAlert\":[],\"UIAlertController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIAlertView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIAppearance\":[\"objc2-foundation/NSArray\"],\"UIApplication\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSData\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObjCRuntime\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\",\"objc2-foundation/NSUserActivity\"],\"UIApplicationShortcutItem\":[\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIAttachmentBehavior\":[\"objc2-foundation/NSArray\"],\"UIBackgroundConfiguration\":[\"objc2-foundation/NSObject\"],\"UIBackgroundExtensionView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIBandSelectionInteraction\":[],\"UIBarAppearance\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIBarButtonItem\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UIBarButtonItemAppearance\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIBarButtonItemBadge\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIBarButtonItemGroup\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIBarCommon\":[],\"UIBarItem\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIBehavioralStyle\":[],\"UIBezierPath\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIBlurEffect\":[\"objc2-foundation/NSObject\"],\"UIButton\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIButtonConfiguration\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UICalendarSelection\":[],\"UICalendarSelectionMultiDate\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCalendar\"],\"UICalendarSelectionSingleDate\":[\"objc2-foundation/NSCalendar\"],\"UICalendarSelectionWeekOfYear\":[\"objc2-foundation/NSCalendar\"],\"UICalendarView\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCalendar\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDateInterval\",\"objc2-foundation/NSLocale\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSTimeZone\"],\"UICalendarViewDecoration\":[],\"UICanvasFeedbackGenerator\":[],\"UICellAccessory\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UICellConfigurationState\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UICloudSharingController\":[\"bitflags\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSData\",\"objc2-foundation/NSError\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UICollectionLayoutList\":[\"bitflags\",\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSObject\"],\"UICollectionView\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSIndexSet\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSProgress\",\"objc2-foundation/NSString\"],\"UICollectionViewCell\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UICollectionViewCompositionalLayout\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UICollectionViewController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UICollectionViewFlowLayout\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSObject\"],\"UICollectionViewItemRegistration\":[\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSString\"],\"UICollectionViewLayout\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UICollectionViewListCell\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UICollectionViewTransitionLayout\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UICollectionViewUpdateItem\":[\"objc2-foundation/NSIndexPath\"],\"UICollisionBehavior\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\"],\"UIColor\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIColorPickerViewController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIColorWell\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UICommand\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIConfigurationColorTransformer\":[],\"UIConfigurationState\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIContentConfiguration\":[\"objc2-foundation/NSObject\"],\"UIContentSizeCategory\":[\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObjCRuntime\",\"objc2-foundation/NSString\"],\"UIContentSizeCategoryAdjusting\":[],\"UIContentUnavailableButtonProperties\":[\"objc2-foundation/NSObject\"],\"UIContentUnavailableConfiguration\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIContentUnavailableConfigurationState\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIContentUnavailableImageProperties\":[\"objc2-foundation/NSObject\"],\"UIContentUnavailableTextProperties\":[\"objc2-foundation/NSObject\"],\"UIContentUnavailableView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIContextMenuConfiguration\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSSet\"],\"UIContextMenuInteraction\":[\"objc2-foundation/NSObject\"],\"UIContextMenuSystem\":[],\"UIContextualAction\":[\"objc2-foundation/NSString\"],\"UIControl\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UIConversationContext\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSPersonNameComponents\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UIConversationEntry\":[\"objc2-foundation/NSDate\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UICornerConfiguration\":[\"objc2-foundation/NSObject\"],\"UICornerRadius\":[\"objc2-foundation/NSObject\"],\"UIDataDetectors\":[\"bitflags\"],\"UIDataSourceTranslating\":[\"objc2-foundation/NSIndexPath\"],\"UIDatePicker\":[\"objc2-foundation/NSCalendar\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSLocale\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSTimeZone\"],\"UIDeferredMenuElement\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIDevice\":[\"objc2-foundation/NSNotification\",\"objc2-foundation/NSString\",\"objc2-foundation/NSUUID\"],\"UIDiffableDataSource\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSOrderedCollectionDifference\",\"objc2-foundation/NSString\"],\"UIDocument\":[\"bitflags\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSFilePresenter\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSProgress\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\",\"objc2-foundation/NSUndoManager\",\"objc2-foundation/NSUserActivity\"],\"UIDocumentBrowserAction\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIDocumentBrowserViewController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSError\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSProgress\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIDocumentInteractionController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIDocumentMenuViewController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIDocumentPickerExtensionViewController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIDocumentPickerViewController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIDocumentProperties\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSURL\"],\"UIDocumentViewController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIDocumentViewControllerLaunchOptions\":[\"objc2-foundation/NSString\"],\"UIDragInteraction\":[\"objc2-foundation/NSArray\"],\"UIDragItem\":[\"objc2-foundation/NSItemProvider\"],\"UIDragPreview\":[\"objc2-foundation/NSObject\"],\"UIDragPreviewParameters\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSValue\"],\"UIDragSession\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSProgress\",\"objc2-foundation/NSString\"],\"UIDropInteraction\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSProgress\"],\"UIDynamicAnimator\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSString\"],\"UIDynamicBehavior\":[\"objc2-foundation/NSArray\"],\"UIDynamicItemBehavior\":[\"objc2-foundation/NSArray\"],\"UIEditMenuInteraction\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\"],\"UIEvent\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSSet\"],\"UIEventAttribution\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIEventAttributionView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIFeedbackGenerator\":[],\"UIFieldBehavior\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSDate\"],\"UIFindInteraction\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"UIFindSession\":[\"objc2-foundation/NSString\"],\"UIFocus\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSString\"],\"UIFocusAnimationCoordinator\":[\"objc2-foundation/NSDate\"],\"UIFocusDebugger\":[],\"UIFocusDefines\":[],\"UIFocusEffect\":[\"objc2-foundation/NSObject\"],\"UIFocusGuide\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\"],\"UIFocusMovementHint\":[\"objc2-foundation/NSObject\"],\"UIFocusSystem\":[],\"UIFocusSystem_UIKitAdditions\":[\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIFocusUpdateContext_UIKitAdditions\":[],\"UIFont\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIFontDescriptor\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UIFontMetrics\":[\"objc2-foundation/NSString\"],\"UIFontPickerViewController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIFontPickerViewControllerConfiguration\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSPredicate\",\"objc2-foundation/NSString\"],\"UIFoundation\":[],\"UIGeometry\":[\"bitflags\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"UIGestureRecognizer\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"UIGestureRecognizerSubclass\":[\"objc2-foundation/NSSet\"],\"UIGlassEffect\":[\"objc2-foundation/NSObject\"],\"UIGraphics\":[\"objc2-foundation/NSData\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIGraphicsImageRenderer\":[\"objc2-foundation/NSData\",\"objc2-foundation/NSObject\"],\"UIGraphicsPDFRenderer\":[\"objc2-foundation/NSData\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIGraphicsRenderer\":[\"objc2-foundation/NSObject\"],\"UIGraphicsRendererSubclass\":[\"objc2-foundation/NSError\"],\"UIGravityBehavior\":[\"objc2-foundation/NSArray\"],\"UIGuidedAccess\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSError\",\"objc2-foundation/NSString\"],\"UIGuidedAccessRestrictions\":[],\"UIHoverEffect\":[\"objc2-foundation/NSObject\"],\"UIHoverEffectLayer\":[\"objc2-foundation/NSObject\"],\"UIHoverGestureRecognizer\":[\"objc2-foundation/NSCoder\"],\"UIHoverStyle\":[\"objc2-foundation/NSObject\"],\"UIImage\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSData\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIImageAsset\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIImageConfiguration\":[\"objc2-foundation/NSLocale\",\"objc2-foundation/NSObject\"],\"UIImagePickerController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"UIImageReader\":[\"objc2-foundation/NSData\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSURL\"],\"UIImageSymbolConfiguration\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSLocale\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIImageView\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSObject\"],\"UIImpactFeedbackGenerator\":[],\"UIIndirectScribbleInteraction\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\"],\"UIInputSuggestion\":[],\"UIInputView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIInputViewController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\",\"objc2-foundation/NSUUID\"],\"UIInteraction\":[\"objc2-foundation/NSArray\"],\"UIInterface\":[],\"UIKey\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIKeyCommand\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIKeyConstants\":[],\"UIKeyboardLayoutGuide\":[\"objc2-foundation/NSObject\"],\"UIKitCore\":[],\"UIKitDefines\":[],\"UILabel\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UILargeContentViewer\":[\"objc2-foundation/NSNotification\",\"objc2-foundation/NSString\"],\"UILayoutGuide\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UILetterformAwareAdjusting\":[],\"UILexicon\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIListContentConfiguration\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIListContentImageProperties\":[\"objc2-foundation/NSObject\"],\"UIListContentTextProperties\":[\"objc2-foundation/NSObject\"],\"UIListSeparatorConfiguration\":[\"objc2-foundation/NSObject\"],\"UILocalNotification\":[\"objc2-foundation/NSCalendar\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSTimeZone\"],\"UILocalizedIndexedCollation\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"UILongPressGestureRecognizer\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDate\"],\"UIMailConversationContext\":[\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UIMailConversationEntry\":[\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UIMainMenuSystem\":[\"objc2-foundation/NSObject\"],\"UIManagedDocument\":[\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSFilePresenter\",\"objc2-foundation/NSProgress\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIMenu\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIMenuBuilder\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"UIMenuController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSString\"],\"UIMenuDisplayPreferences\":[\"objc2-foundation/NSObject\"],\"UIMenuElement\":[\"bitflags\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIMenuLeaf\":[\"objc2-foundation/NSString\"],\"UIMenuSystem\":[],\"UIMessageConversationContext\":[],\"UIMessageConversationEntry\":[],\"UIMotionEffect\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UINavigationBar\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UINavigationBarAppearance\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UINavigationController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UINavigationItem\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\"],\"UINib\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSData\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSString\"],\"UINibDeclarations\":[],\"UINibLoading\":[\"objc2-foundation/NSString\"],\"UINotificationFeedbackGenerator\":[],\"UIOpenURLContext\":[\"objc2-foundation/NSURL\"],\"UIOrientation\":[\"bitflags\"],\"UIPageControl\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIPageControlProgress\":[\"objc2-foundation/NSDate\"],\"UIPageViewController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIPanGestureRecognizer\":[\"bitflags\",\"objc2-foundation/NSCoder\"],\"UIPasteConfiguration\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIPasteConfigurationSupporting\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSItemProvider\"],\"UIPasteControl\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIPasteboard\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSData\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSIndexSet\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIPencilInteraction\":[\"objc2-foundation/NSDate\"],\"UIPickerView\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIPinchGestureRecognizer\":[\"objc2-foundation/NSCoder\"],\"UIPointerAccessory\":[\"objc2-foundation/NSObject\"],\"UIPointerInteraction\":[],\"UIPointerLockState\":[\"objc2-foundation/NSNotification\",\"objc2-foundation/NSString\"],\"UIPointerRegion\":[\"objc2-foundation/NSObject\"],\"UIPointerStyle\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\"],\"UIPopoverBackgroundView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIPopoverController\":[\"objc2-foundation/NSArray\"],\"UIPopoverPresentationController\":[\"objc2-foundation/NSArray\"],\"UIPopoverPresentationControllerSourceItem\":[],\"UIPopoverSupport\":[\"bitflags\"],\"UIPresentationController\":[],\"UIPress\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSDate\"],\"UIPressesEvent\":[\"objc2-foundation/NSSet\"],\"UIPreviewInteraction\":[],\"UIPreviewParameters\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSValue\"],\"UIPrintError\":[\"objc2-foundation/NSError\",\"objc2-foundation/NSString\"],\"UIPrintFormatter\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIPrintInfo\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIPrintInteractionController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSData\",\"objc2-foundation/NSError\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIPrintPageRenderer\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSRange\"],\"UIPrintPaper\":[\"objc2-foundation/NSArray\"],\"UIPrintServiceExtension\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSData\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIPrinter\":[\"bitflags\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UIPrinterPickerController\":[\"objc2-foundation/NSError\"],\"UIProgressView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSProgress\"],\"UIPushBehavior\":[\"objc2-foundation/NSArray\"],\"UIReferenceLibraryViewController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIRefreshControl\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIRegion\":[\"objc2-foundation/NSObject\"],\"UIResponder\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\",\"objc2-foundation/NSUndoManager\",\"objc2-foundation/NSUserActivity\"],\"UIResponder_UIActivityItemsConfiguration\":[],\"UIRotationGestureRecognizer\":[\"objc2-foundation/NSCoder\"],\"UIScene\":[\"objc2-foundation/NSError\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\",\"objc2-foundation/NSUserActivity\"],\"UISceneActivationConditions\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSPredicate\",\"objc2-foundation/NSString\",\"objc2-foundation/NSUserActivity\"],\"UISceneConfiguration\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UISceneDefinitions\":[\"objc2-foundation/NSError\",\"objc2-foundation/NSString\"],\"UISceneDestructionCondition\":[\"objc2-foundation/NSObject\"],\"UISceneEnhancedStateRestoration\":[],\"UISceneOptions\":[\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\",\"objc2-foundation/NSUserActivity\"],\"UISceneSession\":[\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSUserActivity\",\"UISceneConfiguration\"],\"UISceneSessionActivationRequest\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSUserActivity\"],\"UISceneSizeRestrictions\":[],\"UISceneSystemProtectionManager\":[\"objc2-foundation/NSNotification\",\"objc2-foundation/NSString\"],\"UISceneWindowingBehaviors\":[],\"UISceneWindowingControlStyle\":[],\"UIScene_AVAudioSession\":[],\"UIScreen\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSString\"],\"UIScreenEdgePanGestureRecognizer\":[\"objc2-foundation/NSCoder\"],\"UIScreenMode\":[],\"UIScreenshotService\":[\"objc2-foundation/NSData\"],\"UIScribbleInteraction\":[],\"UIScrollEdgeElementContainerInteraction\":[],\"UIScrollView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSSet\"],\"UISearchBar\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"UISearchContainerViewController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UISearchController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UISearchDisplayController\":[\"objc2-foundation/NSString\"],\"UISearchSuggestion\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSString\"],\"UISearchTab\":[\"objc2-foundation/NSString\"],\"UISearchTextField\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UISegmentedControl\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UISelectionFeedbackGenerator\":[],\"UIShadowProperties\":[\"objc2-foundation/NSObject\"],\"UIShape\":[\"objc2-foundation/NSObject\"],\"UISheetPresentationController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"UISlider\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UISliderTrackConfiguration\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UISmartReplySuggestion\":[\"objc2-foundation/NSString\"],\"UISnapBehavior\":[],\"UISplitViewController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UISplitViewControllerLayoutEnvironment\":[],\"UISpringLoadedInteraction\":[],\"UISpringLoadedInteractionSupporting\":[],\"UIStackView\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIStandardTextCursorView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIStateRestoration\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSString\"],\"UIStatusBarManager\":[],\"UIStepper\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIStoryboard\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSString\"],\"UIStoryboardPopoverSegue\":[\"objc2-foundation/NSString\"],\"UIStoryboardSegue\":[\"objc2-foundation/NSString\"],\"UIStringDrawing\":[\"objc2-foundation/NSString\"],\"UISwipeActionsConfiguration\":[\"objc2-foundation/NSArray\"],\"UISwipeGestureRecognizer\":[\"bitflags\",\"objc2-foundation/NSCoder\"],\"UISwitch\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UISymbolContentTransition\":[\"objc2-foundation/NSObject\"],\"UISymbolEffectCompletion\":[],\"UITab\":[\"objc2-foundation/NSString\"],\"UITabAccessory\":[],\"UITabBar\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UITabBarAppearance\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITabBarController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSProgress\",\"objc2-foundation/NSString\"],\"UITabBarControllerSidebar\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSProgress\"],\"UITabBarItem\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITabGroup\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"UITabSidebarItem\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\"],\"UITableView\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSIndexPath\",\"objc2-foundation/NSIndexSet\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSProgress\",\"objc2-foundation/NSString\"],\"UITableViewCell\":[\"bitflags\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITableViewController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITableViewHeaderFooterView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITapGestureRecognizer\":[\"objc2-foundation/NSCoder\"],\"UITargetedDragPreview\":[\"objc2-foundation/NSObject\"],\"UITargetedPreview\":[\"objc2-foundation/NSObject\"],\"UITextChecker\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\"],\"UITextCursorDropPositionAnimator\":[],\"UITextCursorView\":[],\"UITextDragPreviewRenderer\":[\"objc2-foundation/NSRange\"],\"UITextDragURLPreviews\":[\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UITextDragging\":[\"bitflags\",\"objc2-foundation/NSArray\"],\"UITextDropProposal\":[\"objc2-foundation/NSObject\"],\"UITextDropping\":[\"objc2-foundation/NSProgress\"],\"UITextField\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"UITextFormattingCoordinator\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSString\"],\"UITextFormattingViewController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITextFormattingViewControllerChangeValue\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"UITextFormattingViewControllerComponent\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITextFormattingViewControllerConfiguration\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\"],\"UITextFormattingViewControllerFormattingDescriptor\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UITextFormattingViewControllerFormattingStyle\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITextInput\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObjCRuntime\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\"],\"UITextInputContext\":[],\"UITextInputTraits\":[\"bitflags\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITextInteraction\":[\"objc2-foundation/NSArray\"],\"UITextItem\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UITextItemInteraction\":[],\"UITextLoupeSession\":[],\"UITextPasteConfigurationSupporting\":[],\"UITextPasteDelegate\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSItemProvider\",\"objc2-foundation/NSString\"],\"UITextSearching\":[\"objc2-foundation/NSObjCRuntime\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSOrderedSet\",\"objc2-foundation/NSString\"],\"UITextSelectionDisplayInteraction\":[\"objc2-foundation/NSArray\"],\"UITextSelectionHandleView\":[],\"UITextSelectionHighlightView\":[\"objc2-foundation/NSArray\"],\"UITextView\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\",\"objc2-foundation/NSValue\"],\"UITimingCurveProvider\":[\"objc2-foundation/NSObject\"],\"UITimingParameters\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSObject\"],\"UIToolTipInteraction\":[\"objc2-foundation/NSString\"],\"UIToolbar\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIToolbarAppearance\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UITouch\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSValue\"],\"UITrackingLayoutGuide\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\"],\"UITrait\":[\"objc2-foundation/NSString\"],\"UITraitCollection\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UITraitListEnvironment\":[],\"UIUpdateActionPhase\":[],\"UIUpdateInfo\":[\"objc2-foundation/NSDate\"],\"UIUpdateLink\":[],\"UIUserActivity\":[\"objc2-foundation/NSUserActivity\"],\"UIUserNotificationSettings\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"UIVibrancyEffect\":[\"objc2-foundation/NSObject\"],\"UIVideoEditorController\":[\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSError\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIView\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIViewAnimating\":[\"objc2-foundation/NSDate\",\"objc2-foundation/NSObject\"],\"UIViewConfigurationState\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIViewController\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSBundle\",\"objc2-foundation/NSCoder\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSExtensionContext\",\"objc2-foundation/NSExtensionRequestHandling\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObjCRuntime\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIViewControllerTransition\":[],\"UIViewControllerTransitionCoordinator\":[\"objc2-foundation/NSDate\",\"objc2-foundation/NSString\"],\"UIViewControllerTransitioning\":[\"objc2-foundation/NSDate\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIViewLayoutRegion\":[],\"UIViewPropertyAnimator\":[\"objc2-foundation/NSDate\",\"objc2-foundation/NSObject\"],\"UIVisualEffect\":[\"objc2-foundation/NSObject\"],\"UIVisualEffectView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\"],\"UIWebView\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSData\",\"objc2-foundation/NSError\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\",\"objc2-foundation/NSURLRequest\"],\"UIWindow\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSNotification\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIWindowScene\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSError\",\"objc2-foundation/NSString\",\"UISceneSizeRestrictions\"],\"UIWindowSceneActivationAction\":[\"objc2-foundation/NSCoder\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UIWindowSceneActivationConfiguration\":[\"objc2-foundation/NSUserActivity\"],\"UIWindowSceneActivationInteraction\":[\"objc2-foundation/NSError\"],\"UIWindowSceneActivationRequestOptions\":[],\"UIWindowSceneDragInteraction\":[],\"UIWindowSceneGeometry\":[\"objc2-foundation/NSObject\"],\"UIWindowSceneGeometryPreferences\":[],\"UIWindowSceneGeometryPreferencesIOS\":[],\"UIWindowSceneGeometryPreferencesMac\":[],\"UIWindowSceneGeometryPreferencesVision\":[],\"UIWindowScenePlacement\":[\"objc2-foundation/NSObject\"],\"UIWindowSceneProminentPlacement\":[\"objc2-foundation/NSObject\"],\"UIWindowScenePushPlacement\":[\"objc2-foundation/NSObject\"],\"UIWindowSceneReplacePlacement\":[\"objc2-foundation/NSObject\"],\"UIWindowSceneStandardPlacement\":[\"objc2-foundation/NSObject\"],\"UIWritingToolsCoordinator\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSString\",\"objc2-foundation/NSUUID\",\"objc2-foundation/NSValue\"],\"UIWritingToolsCoordinatorAnimationParameters\":[],\"UIWritingToolsCoordinatorContext\":[\"objc2-foundation/NSAttributedString\",\"objc2-foundation/NSRange\",\"objc2-foundation/NSUUID\"],\"UIZoomTransitionOptions\":[\"objc2-foundation/NSObject\"],\"UNNotificationResponse_UIKitAdditions\":[],\"alloc\":[],\"bitflags\":[\"dep:bitflags\"],\"block2\":[\"dep:block2\"],\"default\":[\"std\",\"DocumentManager\",\"NSAdaptiveImageGlyph\",\"NSAttributedString\",\"NSDataAsset\",\"NSDiffableDataSourceSectionSnapshot\",\"NSFileProviderExtension\",\"NSIndexPath_UIKitAdditions\",\"NSItemProvider_UIKitAdditions\",\"NSLayoutAnchor\",\"NSLayoutConstraint\",\"NSLayoutManager\",\"NSParagraphStyle\",\"NSShadow\",\"NSStringDrawing\",\"NSText\",\"NSTextAttachment\",\"NSTextContainer\",\"NSTextContentManager\",\"NSTextElement\",\"NSTextLayoutFragment\",\"NSTextLayoutManager\",\"NSTextLineFragment\",\"NSTextList\",\"NSTextListElement\",\"NSTextRange\",\"NSTextSelection\",\"NSTextSelectionNavigation\",\"NSTextStorage\",\"NSTextViewportLayoutController\",\"NSToolbar_UIKitAdditions\",\"NSTouchBar_UIKitAdditions\",\"NSUserActivity_NSItemProvider\",\"PrintKitUI\",\"ShareSheet\",\"UIAccelerometer\",\"UIAccessibility\",\"UIAccessibilityAdditions\",\"UIAccessibilityConstants\",\"UIAccessibilityContainer\",\"UIAccessibilityContentSizeCategoryImageAdjusting\",\"UIAccessibilityCustomAction\",\"UIAccessibilityCustomRotor\",\"UIAccessibilityElement\",\"UIAccessibilityIdentification\",\"UIAccessibilityLocationDescriptor\",\"UIAccessibilityZoom\",\"UIAction\",\"UIActionSheet\",\"UIActivity\",\"UIActivityCollaborationModeRestriction\",\"UIActivityIndicatorView\",\"UIActivityItemProvider\",\"UIActivityItemsConfiguration\",\"UIActivityItemsConfigurationReading\",\"UIActivityItemsConfigurationReading_ShareSheet\",\"UIActivityViewController\",\"UIAlert\",\"UIAlertController\",\"UIAlertView\",\"UIAppearance\",\"UIApplication\",\"UIApplicationShortcutItem\",\"UIAttachmentBehavior\",\"UIBackgroundConfiguration\",\"UIBackgroundExtensionView\",\"UIBandSelectionInteraction\",\"UIBarAppearance\",\"UIBarButtonItem\",\"UIBarButtonItemAppearance\",\"UIBarButtonItemBadge\",\"UIBarButtonItemGroup\",\"UIBarCommon\",\"UIBarItem\",\"UIBehavioralStyle\",\"UIBezierPath\",\"UIBlurEffect\",\"UIButton\",\"UIButtonConfiguration\",\"UICalendarSelection\",\"UICalendarSelectionMultiDate\",\"UICalendarSelectionSingleDate\",\"UICalendarSelectionWeekOfYear\",\"UICalendarView\",\"UICalendarViewDecoration\",\"UICanvasFeedbackGenerator\",\"UICellAccessory\",\"UICellConfigurationState\",\"UICloudSharingController\",\"UICollectionLayoutList\",\"UICollectionView\",\"UICollectionViewCell\",\"UICollectionViewCompositionalLayout\",\"UICollectionViewController\",\"UICollectionViewFlowLayout\",\"UICollectionViewItemRegistration\",\"UICollectionViewLayout\",\"UICollectionViewListCell\",\"UICollectionViewTransitionLayout\",\"UICollectionViewUpdateItem\",\"UICollisionBehavior\",\"UIColor\",\"UIColorPickerViewController\",\"UIColorWell\",\"UICommand\",\"UIConfigurationColorTransformer\",\"UIConfigurationState\",\"UIContentConfiguration\",\"UIContentSizeCategory\",\"UIContentSizeCategoryAdjusting\",\"UIContentUnavailableButtonProperties\",\"UIContentUnavailableConfiguration\",\"UIContentUnavailableConfigurationState\",\"UIContentUnavailableImageProperties\",\"UIContentUnavailableTextProperties\",\"UIContentUnavailableView\",\"UIContextMenuConfiguration\",\"UIContextMenuInteraction\",\"UIContextMenuSystem\",\"UIContextualAction\",\"UIControl\",\"UIConversationContext\",\"UIConversationEntry\",\"UICornerConfiguration\",\"UICornerRadius\",\"UIDataDetectors\",\"UIDataSourceTranslating\",\"UIDatePicker\",\"UIDeferredMenuElement\",\"UIDevice\",\"UIDiffableDataSource\",\"UIDocument\",\"UIDocumentBrowserAction\",\"UIDocumentBrowserViewController\",\"UIDocumentInteractionController\",\"UIDocumentMenuViewController\",\"UIDocumentPickerExtensionViewController\",\"UIDocumentPickerViewController\",\"UIDocumentProperties\",\"UIDocumentViewController\",\"UIDocumentViewControllerLaunchOptions\",\"UIDragInteraction\",\"UIDragItem\",\"UIDragPreview\",\"UIDragPreviewParameters\",\"UIDragSession\",\"UIDropInteraction\",\"UIDynamicAnimator\",\"UIDynamicBehavior\",\"UIDynamicItemBehavior\",\"UIEditMenuInteraction\",\"UIEvent\",\"UIEventAttribution\",\"UIEventAttributionView\",\"UIFeedbackGenerator\",\"UIFieldBehavior\",\"UIFindInteraction\",\"UIFindSession\",\"UIFocus\",\"UIFocusAnimationCoordinator\",\"UIFocusDebugger\",\"UIFocusDefines\",\"UIFocusEffect\",\"UIFocusGuide\",\"UIFocusMovementHint\",\"UIFocusSystem\",\"UIFocusSystem_UIKitAdditions\",\"UIFocusUpdateContext_UIKitAdditions\",\"UIFont\",\"UIFontDescriptor\",\"UIFontMetrics\",\"UIFontPickerViewController\",\"UIFontPickerViewControllerConfiguration\",\"UIFoundation\",\"UIGeometry\",\"UIGestureRecognizer\",\"UIGestureRecognizerSubclass\",\"UIGlassEffect\",\"UIGraphics\",\"UIGraphicsImageRenderer\",\"UIGraphicsPDFRenderer\",\"UIGraphicsRenderer\",\"UIGraphicsRendererSubclass\",\"UIGravityBehavior\",\"UIGuidedAccess\",\"UIGuidedAccessRestrictions\",\"UIHoverEffect\",\"UIHoverEffectLayer\",\"UIHoverGestureRecognizer\",\"UIHoverStyle\",\"UIImage\",\"UIImageAsset\",\"UIImageConfiguration\",\"UIImagePickerController\",\"UIImageReader\",\"UIImageSymbolConfiguration\",\"UIImageView\",\"UIImpactFeedbackGenerator\",\"UIIndirectScribbleInteraction\",\"UIInputSuggestion\",\"UIInputView\",\"UIInputViewController\",\"UIInteraction\",\"UIInterface\",\"UIKey\",\"UIKeyCommand\",\"UIKeyConstants\",\"UIKeyboardLayoutGuide\",\"UIKitCore\",\"UIKitDefines\",\"UILabel\",\"UILargeContentViewer\",\"UILayoutGuide\",\"UILetterformAwareAdjusting\",\"UILexicon\",\"UIListContentConfiguration\",\"UIListContentImageProperties\",\"UIListContentTextProperties\",\"UIListSeparatorConfiguration\",\"UILocalNotification\",\"UILocalizedIndexedCollation\",\"UILongPressGestureRecognizer\",\"UIMailConversationContext\",\"UIMailConversationEntry\",\"UIMainMenuSystem\",\"UIManagedDocument\",\"UIMenu\",\"UIMenuBuilder\",\"UIMenuController\",\"UIMenuDisplayPreferences\",\"UIMenuElement\",\"UIMenuLeaf\",\"UIMenuSystem\",\"UIMessageConversationContext\",\"UIMessageConversationEntry\",\"UIMotionEffect\",\"UINavigationBar\",\"UINavigationBarAppearance\",\"UINavigationController\",\"UINavigationItem\",\"UINib\",\"UINibDeclarations\",\"UINibLoading\",\"UINotificationFeedbackGenerator\",\"UIOpenURLContext\",\"UIOrientation\",\"UIPageControl\",\"UIPageControlProgress\",\"UIPageViewController\",\"UIPanGestureRecognizer\",\"UIPasteConfiguration\",\"UIPasteConfigurationSupporting\",\"UIPasteControl\",\"UIPasteboard\",\"UIPencilInteraction\",\"UIPickerView\",\"UIPinchGestureRecognizer\",\"UIPointerAccessory\",\"UIPointerInteraction\",\"UIPointerLockState\",\"UIPointerRegion\",\"UIPointerStyle\",\"UIPopoverBackgroundView\",\"UIPopoverController\",\"UIPopoverPresentationController\",\"UIPopoverPresentationControllerSourceItem\",\"UIPopoverSupport\",\"UIPresentationController\",\"UIPress\",\"UIPressesEvent\",\"UIPreviewInteraction\",\"UIPreviewParameters\",\"UIPrintError\",\"UIPrintFormatter\",\"UIPrintInfo\",\"UIPrintInteractionController\",\"UIPrintPageRenderer\",\"UIPrintPaper\",\"UIPrintServiceExtension\",\"UIPrinter\",\"UIPrinterPickerController\",\"UIProgressView\",\"UIPushBehavior\",\"UIReferenceLibraryViewController\",\"UIRefreshControl\",\"UIRegion\",\"UIResponder\",\"UIResponder_UIActivityItemsConfiguration\",\"UIRotationGestureRecognizer\",\"UIScene\",\"UISceneActivationConditions\",\"UISceneConfiguration\",\"UISceneDefinitions\",\"UISceneDestructionCondition\",\"UISceneEnhancedStateRestoration\",\"UISceneOptions\",\"UISceneSession\",\"UISceneSessionActivationRequest\",\"UISceneSizeRestrictions\",\"UISceneSystemProtectionManager\",\"UISceneWindowingBehaviors\",\"UISceneWindowingControlStyle\",\"UIScene_AVAudioSession\",\"UIScreen\",\"UIScreenEdgePanGestureRecognizer\",\"UIScreenMode\",\"UIScreenshotService\",\"UIScribbleInteraction\",\"UIScrollEdgeElementContainerInteraction\",\"UIScrollView\",\"UISearchBar\",\"UISearchContainerViewController\",\"UISearchController\",\"UISearchDisplayController\",\"UISearchSuggestion\",\"UISearchTab\",\"UISearchTextField\",\"UISegmentedControl\",\"UISelectionFeedbackGenerator\",\"UIShadowProperties\",\"UIShape\",\"UISheetPresentationController\",\"UISlider\",\"UISliderTrackConfiguration\",\"UISmartReplySuggestion\",\"UISnapBehavior\",\"UISplitViewController\",\"UISplitViewControllerLayoutEnvironment\",\"UISpringLoadedInteraction\",\"UISpringLoadedInteractionSupporting\",\"UIStackView\",\"UIStandardTextCursorView\",\"UIStateRestoration\",\"UIStatusBarManager\",\"UIStepper\",\"UIStoryboard\",\"UIStoryboardPopoverSegue\",\"UIStoryboardSegue\",\"UIStringDrawing\",\"UISwipeActionsConfiguration\",\"UISwipeGestureRecognizer\",\"UISwitch\",\"UISymbolContentTransition\",\"UISymbolEffectCompletion\",\"UITab\",\"UITabAccessory\",\"UITabBar\",\"UITabBarAppearance\",\"UITabBarController\",\"UITabBarControllerSidebar\",\"UITabBarItem\",\"UITabGroup\",\"UITabSidebarItem\",\"UITableView\",\"UITableViewCell\",\"UITableViewController\",\"UITableViewHeaderFooterView\",\"UITapGestureRecognizer\",\"UITargetedDragPreview\",\"UITargetedPreview\",\"UITextChecker\",\"UITextCursorDropPositionAnimator\",\"UITextCursorView\",\"UITextDragPreviewRenderer\",\"UITextDragURLPreviews\",\"UITextDragging\",\"UITextDropProposal\",\"UITextDropping\",\"UITextField\",\"UITextFormattingCoordinator\",\"UITextFormattingViewController\",\"UITextFormattingViewControllerChangeValue\",\"UITextFormattingViewControllerComponent\",\"UITextFormattingViewControllerConfiguration\",\"UITextFormattingViewControllerFormattingDescriptor\",\"UITextFormattingViewControllerFormattingStyle\",\"UITextInput\",\"UITextInputContext\",\"UITextInputTraits\",\"UITextInteraction\",\"UITextItem\",\"UITextItemInteraction\",\"UITextLoupeSession\",\"UITextPasteConfigurationSupporting\",\"UITextPasteDelegate\",\"UITextSearching\",\"UITextSelectionDisplayInteraction\",\"UITextSelectionHandleView\",\"UITextSelectionHighlightView\",\"UITextView\",\"UITimingCurveProvider\",\"UITimingParameters\",\"UIToolTipInteraction\",\"UIToolbar\",\"UIToolbarAppearance\",\"UITouch\",\"UITrackingLayoutGuide\",\"UITrait\",\"UITraitCollection\",\"UITraitListEnvironment\",\"UIUpdateActionPhase\",\"UIUpdateInfo\",\"UIUpdateLink\",\"UIUserActivity\",\"UIUserNotificationSettings\",\"UIVibrancyEffect\",\"UIVideoEditorController\",\"UIView\",\"UIViewAnimating\",\"UIViewConfigurationState\",\"UIViewController\",\"UIViewControllerTransition\",\"UIViewControllerTransitionCoordinator\",\"UIViewControllerTransitioning\",\"UIViewLayoutRegion\",\"UIViewPropertyAnimator\",\"UIVisualEffect\",\"UIVisualEffectView\",\"UIWebView\",\"UIWindow\",\"UIWindowScene\",\"UIWindowSceneActivationAction\",\"UIWindowSceneActivationConfiguration\",\"UIWindowSceneActivationInteraction\",\"UIWindowSceneActivationRequestOptions\",\"UIWindowSceneDragInteraction\",\"UIWindowSceneGeometry\",\"UIWindowSceneGeometryPreferences\",\"UIWindowSceneGeometryPreferencesIOS\",\"UIWindowSceneGeometryPreferencesMac\",\"UIWindowSceneGeometryPreferencesVision\",\"UIWindowScenePlacement\",\"UIWindowSceneProminentPlacement\",\"UIWindowScenePushPlacement\",\"UIWindowSceneReplacePlacement\",\"UIWindowSceneStandardPlacement\",\"UIWritingToolsCoordinator\",\"UIWritingToolsCoordinatorAnimationParameters\",\"UIWritingToolsCoordinatorContext\",\"UIZoomTransitionOptions\",\"UNNotificationResponse_UIKitAdditions\",\"bitflags\",\"block2\",\"objc2-cloud-kit\",\"objc2-core-data\",\"objc2-core-foundation\",\"objc2-core-graphics\",\"objc2-core-image\",\"objc2-core-location\",\"objc2-core-text\",\"objc2-quartz-core\",\"objc2-user-notifications\"],\"objc2-cloud-kit\":[\"dep:objc2-cloud-kit\"],\"objc2-core-data\":[\"dep:objc2-core-data\"],\"objc2-core-foundation\":[\"dep:objc2-core-foundation\"],\"objc2-core-graphics\":[\"dep:objc2-core-graphics\"],\"objc2-core-image\":[\"dep:objc2-core-image\"],\"objc2-core-location\":[\"dep:objc2-core-location\"],\"objc2-core-text\":[\"dep:objc2-core-text\"],\"objc2-quartz-core\":[\"dep:objc2-quartz-core\"],\"objc2-symbols\":[\"dep:objc2-symbols\"],\"objc2-uniform-type-identifiers\":[\"dep:objc2-uniform-type-identifiers\"],\"objc2-user-notifications\":[\"dep:objc2-user-notifications\"],\"std\":[\"alloc\"],\"unstable-darwin-objc\":[]}}", "objc2-user-notifications_0.3.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bitflags\",\"optional\":true,\"req\":\"^2.5.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"block2\",\"optional\":true,\"req\":\">=0.6.1, <0.8.0\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"objc2\",\"req\":\">=0.6.2, <0.8.0\"},{\"default_features\":false,\"features\":[\"CLRegion\"],\"name\":\"objc2-core-location\",\"optional\":true,\"req\":\"^0.3.2\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"objc2-foundation\",\"req\":\"^0.3.2\"}],\"features\":{\"NSString_UserNotifications\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSString\"],\"UNError\":[\"objc2-foundation/NSString\"],\"UNNotification\":[\"objc2-foundation/NSDate\",\"objc2-foundation/NSObject\"],\"UNNotificationAction\":[\"bitflags\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UNNotificationActionIcon\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UNNotificationAttachment\":[\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSURL\"],\"UNNotificationAttributedMessageContext\":[],\"UNNotificationCategory\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UNNotificationContent\":[\"objc2-foundation/NSArray\",\"objc2-foundation/NSDictionary\",\"objc2-foundation/NSError\",\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\",\"objc2-foundation/NSValue\"],\"UNNotificationRequest\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UNNotificationResponse\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UNNotificationServiceExtension\":[],\"UNNotificationSettings\":[\"objc2-foundation/NSObject\"],\"UNNotificationSound\":[\"objc2-foundation/NSObject\",\"objc2-foundation/NSString\"],\"UNNotificationTrigger\":[\"objc2-foundation/NSCalendar\",\"objc2-foundation/NSDate\",\"objc2-foundation/NSObject\"],\"UNUserNotificationCenter\":[\"bitflags\",\"objc2-foundation/NSArray\",\"objc2-foundation/NSError\",\"objc2-foundation/NSSet\",\"objc2-foundation/NSString\"],\"alloc\":[],\"bitflags\":[\"dep:bitflags\"],\"block2\":[\"dep:block2\"],\"default\":[\"std\",\"NSString_UserNotifications\",\"UNError\",\"UNNotification\",\"UNNotificationAction\",\"UNNotificationActionIcon\",\"UNNotificationAttachment\",\"UNNotificationAttributedMessageContext\",\"UNNotificationCategory\",\"UNNotificationContent\",\"UNNotificationRequest\",\"UNNotificationResponse\",\"UNNotificationServiceExtension\",\"UNNotificationSettings\",\"UNNotificationSound\",\"UNNotificationTrigger\",\"UNUserNotificationCenter\",\"bitflags\",\"block2\",\"objc2-core-location\"],\"objc2-core-location\":[\"dep:objc2-core-location\"],\"std\":[\"alloc\"],\"unstable-darwin-objc\":[]}}", @@ -1581,6 +1584,7 @@ "synstructure_0.13.2": "{\"dependencies\":[{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0.60\"},{\"default_features\":false,\"name\":\"quote\",\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"derive\",\"parsing\",\"printing\",\"clone-impls\",\"visit\",\"extra-traits\"],\"name\":\"syn\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"synstructure_test_traits\",\"req\":\"^0.1\"}],\"features\":{\"default\":[\"proc-macro\"],\"proc-macro\":[\"proc-macro2/proc-macro\",\"syn/proc-macro\",\"quote/proc-macro\"]}}", "syntect_5.3.0": "{\"dependencies\":[{\"name\":\"bincode\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.3\"},{\"name\":\"fancy-regex\",\"optional\":true,\"req\":\"^0.16.2\"},{\"name\":\"flate2\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"fnv\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"getopts\",\"req\":\"^0.2\"},{\"name\":\"once_cell\",\"req\":\"^1.8\"},{\"default_features\":false,\"name\":\"onig\",\"optional\":true,\"req\":\"^6.5.1\"},{\"name\":\"plist\",\"optional\":true,\"req\":\"^1.3\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^0.6\"},{\"kind\":\"dev\",\"name\":\"public-api\",\"req\":\"^0.50.1\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.0\"},{\"name\":\"regex-syntax\",\"optional\":true,\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"rustdoc-json\",\"req\":\"^0.9.7\"},{\"kind\":\"dev\",\"name\":\"rustup-toolchain\",\"req\":\"^0.1.5\"},{\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_derive\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"thiserror\",\"req\":\"^2.0.12\"},{\"name\":\"walkdir\",\"req\":\"^2.0\"},{\"name\":\"yaml-rust\",\"optional\":true,\"req\":\"^0.4.5\"}],\"features\":{\"default\":[\"default-onig\"],\"default-fancy\":[\"parsing\",\"default-syntaxes\",\"default-themes\",\"html\",\"plist-load\",\"yaml-load\",\"dump-load\",\"dump-create\",\"regex-fancy\"],\"default-onig\":[\"parsing\",\"default-syntaxes\",\"default-themes\",\"html\",\"plist-load\",\"yaml-load\",\"dump-load\",\"dump-create\",\"regex-onig\"],\"default-syntaxes\":[\"parsing\",\"dump-load\"],\"default-themes\":[\"dump-load\"],\"dump-create\":[\"flate2\",\"bincode\"],\"dump-load\":[\"flate2\",\"bincode\"],\"html\":[\"parsing\"],\"metadata\":[\"parsing\",\"plist-load\",\"dep:serde_json\"],\"parsing\":[\"regex-syntax\",\"fnv\",\"dump-create\",\"dump-load\"],\"plist-load\":[\"plist\",\"dep:serde_json\"],\"regex-fancy\":[\"fancy-regex\"],\"regex-onig\":[\"onig\"],\"yaml-load\":[\"yaml-rust\",\"parsing\"]}}", "sys-locale_0.3.2": "{\"dependencies\":[{\"name\":\"js-sys\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", not(unix)))\"},{\"name\":\"libc\",\"req\":\"^0.2\",\"target\":\"cfg(target_os = \\\"android\\\")\"},{\"name\":\"wasm-bindgen\",\"optional\":true,\"req\":\"^0.2\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", not(unix)))\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", not(unix)))\"},{\"features\":[\"Window\",\"WorkerGlobalScope\",\"Navigator\",\"WorkerNavigator\"],\"name\":\"web-sys\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", not(unix)))\"}],\"features\":{\"js\":[\"js-sys\",\"wasm-bindgen\",\"web-sys\"]}}", + "sysinfo_0.39.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bstr\",\"req\":\"^1.9.0\"},{\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.14.0\"},{\"name\":\"libc\",\"req\":\"^0.2.173\",\"target\":\"cfg(not(any(target_os = \\\"unknown\\\", target_arch = \\\"wasm32\\\")))\"},{\"name\":\"memchr\",\"optional\":true,\"req\":\"^2.5\"},{\"name\":\"ntapi\",\"optional\":true,\"req\":\"^0.4\",\"target\":\"cfg(windows)\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"objc2-core-foundation\",\"optional\":true,\"req\":\"^0.3.2\",\"target\":\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"ios\\\"))\"},{\"default_features\":false,\"features\":[\"std\",\"libc\"],\"name\":\"objc2-io-kit\",\"optional\":true,\"req\":\"^0.3.2\",\"target\":\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"ios\\\"))\"},{\"default_features\":false,\"features\":[\"objc2-core-foundation\",\"std\",\"CFODNode\",\"CFODSession\",\"CFODQuery\",\"CFODRecord\",\"CFOpenDirectory\",\"CFOpenDirectoryConstants\"],\"name\":\"objc2-open-directory\",\"optional\":true,\"req\":\"^0.3.2\",\"target\":\"cfg(target_os = \\\"macos\\\")\"},{\"name\":\"rayon\",\"optional\":true,\"req\":\"^1.8\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.190\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.9\"},{\"name\":\"windows\",\"optional\":true,\"req\":\">=0.62, <0.63\",\"target\":\"cfg(windows)\"}],\"features\":{\"apple-app-store\":[\"apple-sandbox\"],\"apple-sandbox\":[],\"c-interface\":[\"default\"],\"component\":[\"dep:windows\",\"windows/Win32_Foundation\",\"windows/Win32_Security\",\"windows/Win32_System_Com\",\"windows/Win32_System_Ole\",\"windows/Win32_System_Rpc\",\"windows/Win32_System_Variant\",\"windows/Win32_System_Wmi\",\"dep:objc2-core-foundation\",\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFBase\",\"objc2-core-foundation/CFDictionary\",\"objc2-core-foundation/CFNumber\",\"objc2-core-foundation/CFString\",\"dep:objc2-io-kit\",\"objc2-io-kit/hidsystem\"],\"debug\":[\"libc/extra_traits\"],\"default\":[\"component\",\"disk\",\"network\",\"system\",\"user\"],\"disk\":[\"dep:windows\",\"windows/Win32_Foundation\",\"windows/Win32_Storage_FileSystem\",\"windows/Win32_Security\",\"windows/Win32_System_IO\",\"windows/Win32_System_Ioctl\",\"windows/Win32_System_SystemServices\",\"windows/Win32_System_WindowsProgramming\",\"dep:objc2-core-foundation\",\"objc2-core-foundation/CFArray\",\"objc2-core-foundation/CFBase\",\"objc2-core-foundation/CFDictionary\",\"objc2-core-foundation/CFError\",\"objc2-core-foundation/CFNumber\",\"objc2-core-foundation/CFString\",\"objc2-core-foundation/CFURL\",\"dep:objc2-io-kit\"],\"linux-netdevs\":[],\"linux-tmpfs\":[],\"multithread\":[\"dep:rayon\"],\"network\":[\"dep:windows\",\"windows/Win32_Foundation\",\"windows/Win32_NetworkManagement_IpHelper\",\"windows/Win32_NetworkManagement_Ndis\",\"windows/Win32_Networking_WinSock\"],\"serde\":[\"dep:serde\"],\"system\":[\"dep:windows\",\"windows/Win32_Foundation\",\"windows/Win32_System_Diagnostics_ToolHelp\",\"windows/Wdk_System_SystemInformation\",\"windows/Wdk_System_SystemServices\",\"windows/Wdk_System_Threading\",\"windows/Win32_Security_Authorization\",\"windows/Win32_System_Diagnostics_Debug\",\"windows/Win32_System_Kernel\",\"windows/Win32_System_Memory\",\"windows/Win32_System_Performance\",\"windows/Win32_System_Power\",\"windows/Win32_System_ProcessStatus\",\"windows/Win32_System_Registry\",\"windows/Win32_System_RemoteDesktop\",\"windows/Win32_System_SystemInformation\",\"windows/Win32_System_SystemServices\",\"windows/Win32_System_Threading\",\"windows/Win32_UI_Shell\",\"dep:ntapi\",\"dep:memchr\",\"dep:objc2-core-foundation\",\"objc2-core-foundation/CFBase\",\"objc2-core-foundation/CFData\",\"objc2-core-foundation/CFDictionary\",\"objc2-core-foundation/CFString\",\"dep:objc2-io-kit\"],\"unknown-ci\":[],\"user\":[\"dep:windows\",\"windows/Win32_Foundation\",\"windows/Win32_NetworkManagement_NetManagement\",\"windows/Win32_Security\",\"windows/Win32_Security_Authentication_Identity\",\"windows/Win32_Security_Authorization\",\"dep:objc2-core-foundation\",\"objc2-core-foundation/CFString\",\"dep:objc2-open-directory\"]}}", "system-configuration-sys_0.6.0": "{\"dependencies\":[{\"name\":\"core-foundation-sys\",\"req\":\"^0.8\"},{\"name\":\"libc\",\"req\":\"^0.2.149\"}],\"features\":{}}", "system-configuration_0.7.0": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2\"},{\"name\":\"core-foundation\",\"req\":\"^0.9\"},{\"name\":\"system-configuration-sys\",\"req\":\"^0.6\"}],\"features\":{}}", "system-deps_7.0.7": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"assert_matches\",\"req\":\"^1.5\"},{\"features\":[\"targets\"],\"name\":\"cfg-expr\",\"req\":\">=0.17, <0.21\"},{\"name\":\"heck\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"itertools\",\"req\":\"^0.14\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1\"},{\"name\":\"pkg-config\",\"req\":\"^0.3.25\"},{\"default_features\":false,\"features\":[\"parse\",\"std\"],\"name\":\"toml\",\"req\":\"^0.9\"},{\"name\":\"version-compare\",\"req\":\"^0.2\"}],\"features\":{}}", diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index 547a05774a..4d83ac042f 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -2333,6 +2333,7 @@ dependencies = [ "sqlx", "supports-color 3.0.2", "sys-locale", + "sysinfo", "tempfile", "tokio", "toml 0.9.11+spec-1.1.0", @@ -9210,6 +9211,15 @@ dependencies = [ "bitflags 2.10.0", ] +[[package]] +name = "ntapi" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae" +dependencies = [ + "winapi", +] + [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -9474,6 +9484,16 @@ dependencies = [ "objc2-core-foundation", ] +[[package]] +name = "objc2-io-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" +dependencies = [ + "libc", + "objc2-core-foundation", +] + [[package]] name = "objc2-io-surface" version = "0.3.2" @@ -9485,6 +9505,17 @@ dependencies = [ "objc2-core-foundation", ] +[[package]] +name = "objc2-open-directory" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb82bed227edf5201dfedf072bba4015a33d3d4a98519837295a90f0a23f676d" +dependencies = [ + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + [[package]] name = "objc2-quartz-core" version = "0.3.2" @@ -13010,6 +13041,21 @@ dependencies = [ "libc", ] +[[package]] +name = "sysinfo" +version = "0.39.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21d0d938c10fcda3e897e28aaddf4ab462375d411f4378cd63b1c945f69aba96" +dependencies = [ + "libc", + "memchr", + "ntapi", + "objc2-core-foundation", + "objc2-io-kit", + "objc2-open-directory", + "windows 0.62.2", +] + [[package]] name = "system-configuration" version = "0.7.0" diff --git a/codex-rs/Cargo.toml b/codex-rs/Cargo.toml index dfb89a02c5..2907ffeaf2 100644 --- a/codex-rs/Cargo.toml +++ b/codex-rs/Cargo.toml @@ -400,6 +400,7 @@ strum = "0.27.2" strum_macros = "0.28.0" supports-color = "3.0.2" syntect = "5" +sysinfo = "0.39.3" sys-locale = "0.3.2" tar = { version = "=0.4.45", default-features = false } tempfile = "3.23.0" diff --git a/codex-rs/cli/Cargo.toml b/codex-rs/cli/Cargo.toml index 8896759f98..9ceb54fcc8 100644 --- a/codex-rs/cli/Cargo.toml +++ b/codex-rs/cli/Cargo.toml @@ -68,6 +68,7 @@ regex-lite = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } supports-color = { workspace = true } +sysinfo = { workspace = true } sys-locale = { workspace = true } tempfile = { workspace = true } tokio = { workspace = true, features = [ diff --git a/codex-rs/cli/src/doctor.rs b/codex-rs/cli/src/doctor.rs index c0f310e700..b1a71da420 100644 --- a/codex-rs/cli/src/doctor.rs +++ b/codex-rs/cli/src/doctor.rs @@ -1,14 +1,14 @@ //! Implements the `codex doctor` diagnostic report. //! -//! Doctor is intentionally read-mostly: checks inspect the current installation, +//! Doctor is read-only by default: checks inspect the current installation, //! configuration, authentication, terminal, state paths, and bounded reachability //! probes without attempting repair or starting long-lived services. Each check //! returns a redacted, serializable row so the same data can back the human //! summary and `--json` support report. //! -//! A failing check should describe the problem and remediation, but it should not -//! mutate user state. That keeps the command safe to run before filing a support -//! issue or while diagnosing a broken local installation. +//! A failing check should describe the problem and remediation. The explicit, +//! interactive `--fix` path is reserved for narrowly scoped repairs that create +//! backups before mutating user state. use std::collections::BTreeMap; use std::collections::BTreeSet; @@ -66,16 +66,19 @@ use serde::Serialize; use supports_color::Stream; mod background; +mod fix; mod git; mod output; mod progress; mod runtime; +mod state_migrations; mod system; mod thread_inventory; mod title; mod updates; use background::background_server_check; +use fix::run_migration_fix; use git::git_check; use output::HumanOutputOptions; use output::redact_detail; @@ -84,6 +87,7 @@ use progress::DoctorProgress; use progress::doctor_progress; use runtime::runtime_check; use runtime::search_check; +use state_migrations::migration_check; use system::system_check; use thread_inventory::thread_inventory_check; use title::terminal_title_check; @@ -152,6 +156,10 @@ pub struct DoctorCommand { #[arg(long, default_value_t = false)] json: bool, + /// Repair incompatible state database migration history after confirmation. + #[arg(long, default_value_t = false, conflicts_with = "json")] + fix: bool, + /// Only show grouped check rows and the final count summary. #[arg(long, default_value_t = false)] summary: bool, @@ -300,15 +308,21 @@ impl DoctorCheck { /// Builds, renders, and exits according to the current doctor report. /// -/// This is the CLI entry point for codex doctor. It does not repair issues; -/// failures are represented in the report and cause a non-zero process exit so -/// scripts can distinguish a clean environment from one that needs attention. +/// This is the CLI entry point for codex doctor. Checks are read-only unless the +/// user explicitly selects and confirms `--fix`. pub async fn run_doctor( command: DoctorCommand, root_config_overrides: CliConfigOverrides, interactive: &TuiCli, arg0_paths: &Arg0DispatchPaths, ) -> anyhow::Result<()> { + if command.fix { + let config = load_config(root_config_overrides.clone(), interactive, arg0_paths) + .await + .context("failed to load Codex config for database repair")?; + let inspections = codex_state::inspect_runtime_db_migrations(&config.sqlite_home).await; + run_migration_fix(&config, &inspections).await?; + } let report = build_report(&command, root_config_overrides, interactive, arg0_paths).await; if command.json { @@ -364,6 +378,7 @@ async fn build_report( git_check, terminal_title_check, state_check, + migration_check, thread_inventory_check, background_server_check, reachability_check, @@ -395,6 +410,11 @@ async fn build_report( }) }, run_async_check("state", progress.clone(), state_check(config)), + run_async_check( + "state migrations", + progress.clone(), + migration_check(config), + ), run_async_check( "thread inventory", progress.clone(), @@ -423,6 +443,7 @@ async fn build_report( git_check, terminal_title_check, state_check, + migration_check, thread_inventory_check, background_server_check, reachability_check, diff --git a/codex-rs/cli/src/doctor/fix.rs b/codex-rs/cli/src/doctor/fix.rs new file mode 100644 index 0000000000..2f33f8be74 --- /dev/null +++ b/codex-rs/cli/src/doctor/fix.rs @@ -0,0 +1,279 @@ +//! Interactive repair for incompatible runtime database migration metadata. + +use std::io::IsTerminal; +use std::io::Write; +use std::path::Path; +use std::path::PathBuf; +use std::time::Duration; +use std::time::Instant; + +use anyhow::Context; +use anyhow::bail; +use codex_app_server_daemon::LifecycleCommand; +use codex_core::config::Config; +use codex_state::RuntimeDbMigrationInspection; +use codex_state::RuntimeDbMigrationStatus; +use sysinfo::Pid; +use sysinfo::ProcessesToUpdate; +use sysinfo::Signal; +use sysinfo::System; + +use super::state_migrations::incompatible_database_paths; + +const PROCESS_STOP_TIMEOUT: Duration = Duration::from_secs(5); +const PROCESS_POLL_INTERVAL: Duration = Duration::from_millis(100); +const PROCESS_STABLE_WINDOW: Duration = Duration::from_secs(1); + +#[derive(Clone, Debug, Eq, PartialEq)] +struct AppServerProcess { + pid: Pid, + executable: PathBuf, +} + +pub(super) async fn run_migration_fix( + config: &Config, + inspections: &[RuntimeDbMigrationInspection], +) -> anyhow::Result { + let database_paths = incompatible_database_paths(inspections); + if database_paths.is_empty() { + return Ok(false); + } + if !(std::io::stdin().is_terminal() && std::io::stderr().is_terminal()) { + bail!( + "cannot repair state databases without an interactive terminal; rerun `codex doctor --fix` in a terminal" + ); + } + + let processes = app_server_processes(); + if !confirm_repair(&database_paths, &processes)? { + eprintln!("No changes made."); + return Ok(false); + } + + stop_managed_daemon().await; + stop_app_server_processes().await?; + + let mut backup_folders = Vec::new(); + for path in &database_paths { + let backups = codex_state::backup_runtime_db_for_fresh_start(path) + .await + .with_context(|| format!("failed to back up {}", path.display()))?; + if let Some(folder) = backups + .first() + .and_then(|backup| backup.backup_path.parent()) + .map(Path::to_path_buf) + && !backup_folders.contains(&folder) + { + backup_folders.push(folder); + } + } + + let runtime = codex_state::StateRuntime::init( + config.sqlite_home.clone(), + config.model_provider_id.clone(), + ) + .await + .context("failed to rebuild Codex runtime databases")?; + runtime.close().await; + + let post_repair = codex_state::inspect_runtime_db_migrations(&config.sqlite_home).await; + if let Some(inspection) = post_repair.iter().find(|inspection| { + matches!( + inspection.status, + RuntimeDbMigrationStatus::Incompatible(_) | RuntimeDbMigrationStatus::Unreadable(_) + ) + }) { + bail!( + "rebuilt {} still has incompatible migration metadata at {}", + inspection.label, + inspection.path.display() + ); + } + + eprintln!("Codex rebuilt the affected runtime database."); + for backup_folder in backup_folders { + eprintln!("Backup folder: {}", backup_folder.display()); + } + eprintln!("App servers remain stopped."); + eprintln!("Reopen the Codex Desktop App or run `codex app-server daemon start` when ready."); + Ok(true) +} + +fn confirm_repair( + database_paths: &[PathBuf], + processes: &[AppServerProcess], +) -> std::io::Result { + let mut stderr = std::io::stderr().lock(); + writeln!( + stderr, + "Codex found incompatible database migration history:" + )?; + for path in database_paths { + writeln!(stderr, " - {}", path.display())?; + } + writeln!( + stderr, + "The affected database and SQLite sidecars will be moved to a backup folder before a fresh database is created." + )?; + if processes.is_empty() { + writeln!( + stderr, + "No running Codex app-server processes were detected." + )?; + } else { + writeln!( + stderr, + "The following Codex app-server processes will be stopped, interrupting active work:" + )?; + for process in processes { + writeln!( + stderr, + " - PID {}: {}", + process.pid, + process.executable.display() + )?; + } + } + write!(stderr, "Continue? [y/N]: ")?; + stderr.flush()?; + + let mut input = String::new(); + std::io::stdin().read_line(&mut input)?; + let answer = input.trim(); + Ok(answer.eq_ignore_ascii_case("y") || answer.eq_ignore_ascii_case("yes")) +} + +async fn stop_managed_daemon() { + if let Err(err) = codex_app_server_daemon::run(LifecycleCommand::Stop).await { + eprintln!("Could not stop the managed app-server daemon directly: {err}"); + } +} + +async fn stop_app_server_processes() -> anyhow::Result<()> { + signal_app_server_processes(/*force*/ false)?; + if wait_for_app_servers_to_stop(PROCESS_STOP_TIMEOUT).await { + return Ok(()); + } + + signal_app_server_processes(/*force*/ true)?; + if wait_for_app_servers_to_stop(PROCESS_STOP_TIMEOUT).await { + return Ok(()); + } + + let remaining = app_server_processes(); + let remaining_pids = remaining + .iter() + .map(|process| process.pid.to_string()) + .collect::>() + .join(", "); + bail!( + "Codex app-server processes are still running or were restarted (PIDs: {remaining_pids}). Quit the Codex Desktop App and any editor integrations, then rerun `codex doctor --fix`. No database files were changed." + ) +} + +fn signal_app_server_processes(force: bool) -> anyhow::Result<()> { + let mut system = System::new(); + system.refresh_processes(ProcessesToUpdate::All, /*remove_dead_processes*/ true); + let current_pid = Pid::from_u32(std::process::id()); + let mut failed = Vec::new(); + for (pid, process) in system.processes() { + if *pid == current_pid + || !is_app_server_process(process.name(), process.exe(), process.cmd()) + { + continue; + } + let signaled = if force { + process.kill() + } else { + process + .kill_with(Signal::Term) + .unwrap_or_else(|| process.kill()) + }; + if !signaled { + failed.push(pid.to_string()); + } + } + if failed.is_empty() { + Ok(()) + } else { + bail!( + "failed to stop Codex app-server processes with PIDs: {}", + failed.join(", ") + ) + } +} + +async fn wait_for_app_servers_to_stop(timeout: Duration) -> bool { + let deadline = Instant::now() + timeout; + let mut empty_since = None; + loop { + if app_server_processes().is_empty() { + let empty_since = empty_since.get_or_insert_with(Instant::now); + if empty_since.elapsed() >= PROCESS_STABLE_WINDOW { + return true; + } + } else { + empty_since = None; + } + if Instant::now() >= deadline { + return false; + } + tokio::time::sleep(PROCESS_POLL_INTERVAL).await; + } +} + +fn app_server_processes() -> Vec { + let mut system = System::new(); + system.refresh_processes(ProcessesToUpdate::All, /*remove_dead_processes*/ true); + let current_pid = Pid::from_u32(std::process::id()); + system + .processes() + .iter() + .filter_map(|(pid, process)| { + if *pid == current_pid + || !is_app_server_process(process.name(), process.exe(), process.cmd()) + { + return None; + } + Some(AppServerProcess { + pid: *pid, + executable: process + .exe() + .map(Path::to_path_buf) + .unwrap_or_else(|| PathBuf::from(process.name())), + }) + }) + .collect() +} + +fn is_app_server_process( + process_name: &std::ffi::OsStr, + executable: Option<&Path>, + command: &[std::ffi::OsString], +) -> bool { + let executable_name = executable + .and_then(Path::file_name) + .unwrap_or(process_name) + .to_string_lossy() + .to_ascii_lowercase(); + if executable_name.contains("codex-app-server") { + return true; + } + if !executable_name.starts_with("codex") { + return false; + } + + let args = command + .iter() + .map(|arg| arg.to_string_lossy().to_ascii_lowercase()) + .collect::>(); + let Some(app_server_index) = args.iter().position(|arg| arg == "app-server") else { + return false; + }; + args.get(app_server_index + 1) + .is_none_or(|arg| arg != "daemon") +} + +#[cfg(test)] +#[path = "fix_tests.rs"] +mod tests; diff --git a/codex-rs/cli/src/doctor/fix_tests.rs b/codex-rs/cli/src/doctor/fix_tests.rs new file mode 100644 index 0000000000..12f62273ad --- /dev/null +++ b/codex-rs/cli/src/doctor/fix_tests.rs @@ -0,0 +1,52 @@ +use std::ffi::OsStr; +use std::ffi::OsString; + +use super::*; + +fn args(values: &[&str]) -> Vec { + values.iter().map(OsString::from).collect() +} + +#[test] +fn recognizes_cli_and_standalone_app_servers() { + assert!(is_app_server_process( + OsStr::new("codex"), + Some(Path::new("/usr/bin/codex")), + &args(&["codex", "app-server", "--listen", "stdio://"]), + )); + assert!(is_app_server_process( + OsStr::new("codex-app-server"), + Some(Path::new("/usr/bin/codex-app-server")), + &args(&["codex-app-server"]), + )); +} + +#[test] +fn excludes_daemon_commands_and_unrelated_codex_processes() { + assert!(!is_app_server_process( + OsStr::new("codex"), + Some(Path::new("/usr/bin/codex")), + &args(&["codex", "app-server", "daemon", "pid-update-loop"]), + )); + assert!(!is_app_server_process( + OsStr::new("codex"), + Some(Path::new("/usr/bin/codex")), + &args(&["codex", "doctor", "--fix"]), + )); +} + +#[tokio::test] +async fn no_incompatible_database_skips_interactive_repair() { + let temp = tempfile::tempdir().expect("tempdir"); + let config = codex_core::config::ConfigBuilder::default() + .codex_home(temp.path().to_path_buf()) + .build() + .await + .expect("config"); + + let repaired = run_migration_fix(&config, &[]) + .await + .expect("repair result"); + + assert!(!repaired); +} diff --git a/codex-rs/cli/src/doctor/output.rs b/codex-rs/cli/src/doctor/output.rs index 81f9231482..914b6e0d10 100644 --- a/codex-rs/cli/src/doctor/output.rs +++ b/codex-rs/cli/src/doctor/output.rs @@ -26,8 +26,16 @@ const GROUPS: &[OutputGroup] = &[ OutputGroup { title: "Environment", keys: &[ - "system", "runtime", "install", "search", "git", "terminal", "title", "state", + "system", + "runtime", + "install", + "search", + "git", + "terminal", + "title", + "state", "threads", + "migrations", ], }, OutputGroup { diff --git a/codex-rs/cli/src/doctor/snapshots/codex__doctor__state_migrations__tests__doctor_migration_conflict.snap b/codex-rs/cli/src/doctor/snapshots/codex__doctor__state_migrations__tests__doctor_migration_conflict.snap new file mode 100644 index 0000000000..f6871b2fd7 --- /dev/null +++ b/codex-rs/cli/src/doctor/snapshots/codex__doctor__state_migrations__tests__doctor_migration_conflict.snap @@ -0,0 +1,21 @@ +--- +source: cli/src/doctor/state_migrations_tests.rs +expression: rendered +--- +Codex Doctor v0.0.0-test + +Notes + [XX] migrations state DB migration 36 was previously applied but has been modified +------------------------------------------------------------- + +Environment + [XX] migrations state DB migration 36 was previously applied but has been modified + state DB migration database /Users/example/.codex/state_5.sqlite + > state DB migrations state DB migration 36 was previously applied but has been modified (expected embedded migration metadata) + -> run codex doctor --fix + +------------------------------------------------------------- +0 ok | 1 notes | 0 warn | 1 fail failed + +--summary compact output --all expand truncated lists +--json redacted report diff --git a/codex-rs/cli/src/doctor/state_migrations.rs b/codex-rs/cli/src/doctor/state_migrations.rs new file mode 100644 index 0000000000..027d9b91b0 --- /dev/null +++ b/codex-rs/cli/src/doctor/state_migrations.rs @@ -0,0 +1,128 @@ +//! Reports runtime database migration compatibility without applying migrations. + +use std::path::PathBuf; + +use codex_core::config::Config; +use codex_state::RuntimeDbMigrationInspection; +use codex_state::RuntimeDbMigrationIssue; +use codex_state::RuntimeDbMigrationStatus; + +use super::CheckStatus; +use super::DoctorCheck; +use super::DoctorIssue; + +pub(super) async fn migration_check(config: &Config) -> DoctorCheck { + migration_check_from_inspections( + codex_state::inspect_runtime_db_migrations(&config.sqlite_home).await, + ) +} + +pub(super) fn incompatible_database_paths( + inspections: &[RuntimeDbMigrationInspection], +) -> Vec { + inspections + .iter() + .filter(|&inspection| { + matches!(inspection.status, RuntimeDbMigrationStatus::Incompatible(_)) + }) + .map(|inspection| inspection.path.clone()) + .collect() +} + +pub(super) fn migration_check_from_inspections( + inspections: Vec, +) -> DoctorCheck { + let mut details = Vec::new(); + let mut issues = Vec::new(); + let mut has_incompatible = false; + let mut has_unreadable = false; + + for inspection in inspections { + match inspection.status { + RuntimeDbMigrationStatus::Missing => { + details.push(format!( + "{} migrations: skipped (missing)", + inspection.label + )); + } + RuntimeDbMigrationStatus::Compatible { applied, pending } => { + details.push(format!( + "{} migrations: compatible ({applied} applied, {pending} pending)", + inspection.label + )); + } + RuntimeDbMigrationStatus::Incompatible(db_issues) => { + has_incompatible = true; + details.push(format!( + "{} migration database: {}", + inspection.label, + inspection.path.display() + )); + for issue in db_issues { + let cause = migration_issue_cause(inspection.label, &issue); + details.push(format!("{} migrations: {cause}", inspection.label)); + issues.push( + DoctorIssue::new(CheckStatus::Fail, cause) + .measured("applied migration metadata") + .expected("embedded migration metadata") + .remedy("run codex doctor --fix") + .field(format!("{} migrations", inspection.label)), + ); + } + } + RuntimeDbMigrationStatus::Unreadable(error) => { + has_unreadable = true; + details.push(format!( + "{} migrations: unreadable ({error})", + inspection.label + )); + } + } + } + + let (status, summary) = if has_incompatible { + ( + CheckStatus::Fail, + "state database migration history is incompatible", + ) + } else if has_unreadable { + ( + CheckStatus::Fail, + "state database migration history could not be inspected", + ) + } else { + ( + CheckStatus::Ok, + "state database migration history is compatible", + ) + }; + let mut check = + DoctorCheck::new("state.migrations", "migrations", status, summary).details(details); + for issue in issues { + check = check.issue(issue); + } + if has_incompatible { + check = check.remediation( + "Run `codex doctor --fix` to stop Codex app servers, back up the affected database, and rebuild it.", + ); + } else if has_unreadable { + check = check + .remediation("Resolve the reported SQLite access error, then rerun `codex doctor`."); + } + check +} + +fn migration_issue_cause(label: &str, issue: &RuntimeDbMigrationIssue) -> String { + match issue { + RuntimeDbMigrationIssue::Dirty { version } => { + format!("{label} migration {version} is partially applied") + } + RuntimeDbMigrationIssue::ChecksumMismatch { version } => { + format!("{label} migration {version} was previously applied but has been modified") + } + } +} + +#[cfg(test)] +#[path = "state_migrations_tests.rs"] +mod tests; diff --git a/codex-rs/cli/src/doctor/state_migrations_tests.rs b/codex-rs/cli/src/doctor/state_migrations_tests.rs new file mode 100644 index 0000000000..776d07f85b --- /dev/null +++ b/codex-rs/cli/src/doctor/state_migrations_tests.rs @@ -0,0 +1,97 @@ +use std::path::PathBuf; + +use codex_state::RuntimeDbMigrationInspection; +use codex_state::RuntimeDbMigrationIssue; +use codex_state::RuntimeDbMigrationStatus; +use pretty_assertions::assert_eq; + +use super::super::DoctorReport; +use super::super::output::HumanOutputOptions; +use super::super::output::render_human_report; +use super::*; + +#[test] +fn checksum_mismatch_is_fixable_failure() { + let path = PathBuf::from("/tmp/state_5.sqlite"); + let inspections = vec![RuntimeDbMigrationInspection { + label: "state DB", + path: path.clone(), + status: RuntimeDbMigrationStatus::Incompatible(vec![ + RuntimeDbMigrationIssue::ChecksumMismatch { version: 36 }, + ]), + }]; + + let check = migration_check_from_inspections(inspections.clone()); + + assert_eq!(check.id, "state.migrations"); + assert_eq!(check.status, CheckStatus::Fail); + assert_eq!( + check.summary, + "state database migration history is incompatible" + ); + assert_eq!(incompatible_database_paths(&inspections), vec![path]); + assert_eq!(check.issues.len(), 1); + assert_eq!( + check.remediation.as_deref(), + Some( + "Run `codex doctor --fix` to stop Codex app servers, back up the affected database, and rebuild it." + ) + ); +} + +#[test] +fn compatible_and_missing_databases_stay_ok() { + let inspections = vec![ + RuntimeDbMigrationInspection { + label: "state DB", + path: PathBuf::from("state_5.sqlite"), + status: RuntimeDbMigrationStatus::Compatible { + applied: 37, + pending: 0, + }, + }, + RuntimeDbMigrationInspection { + label: "log DB", + path: PathBuf::from("logs_2.sqlite"), + status: RuntimeDbMigrationStatus::Missing, + }, + ]; + + let check = migration_check_from_inspections(inspections); + + assert_eq!(check.status, CheckStatus::Ok); + assert_eq!( + check.summary, + "state database migration history is compatible" + ); +} + +#[test] +fn migration_conflict_has_human_snapshot_coverage() { + let check = migration_check_from_inspections(vec![RuntimeDbMigrationInspection { + label: "state DB", + path: PathBuf::from("/Users/example/.codex/state_5.sqlite"), + status: RuntimeDbMigrationStatus::Incompatible(vec![ + RuntimeDbMigrationIssue::ChecksumMismatch { version: 36 }, + ]), + }]); + let report = DoctorReport { + schema_version: 1, + generated_at: "2026-06-15T12:00:00Z".to_string(), + overall_status: CheckStatus::Fail, + codex_version: "0.0.0-test".to_string(), + checks: vec![check], + }; + + let rendered = render_human_report( + &report, + HumanOutputOptions { + show_details: true, + show_all: false, + ascii: true, + color_enabled: false, + }, + ); + + insta::assert_snapshot!("doctor_migration_conflict", rendered); +} diff --git a/codex-rs/cli/src/main.rs b/codex-rs/cli/src/main.rs index 1d06ee7872..6cd66d0900 100644 --- a/codex-rs/cli/src/main.rs +++ b/codex-rs/cli/src/main.rs @@ -3475,6 +3475,22 @@ mod tests { ); } + #[test] + fn doctor_fix_parses() { + let cli = MultitoolCli::try_parse_from(["codex", "doctor", "--fix"]) + .expect("doctor --fix should parse"); + + assert!(matches!(cli.subcommand, Some(Subcommand::Doctor(_)))); + } + + #[test] + fn doctor_fix_rejects_json_output() { + let error = MultitoolCli::try_parse_from(["codex", "doctor", "--fix", "--json"]) + .expect_err("doctor --fix --json should be rejected"); + + assert_eq!(error.kind(), clap::error::ErrorKind::ArgumentConflict); + } + #[test] fn root_strict_config_is_supported_for_exec_server() { let cli = MultitoolCli::try_parse_from(["codex", "--strict-config", "exec-server"]) diff --git a/codex-rs/cli/src/state_db_recovery.rs b/codex-rs/cli/src/state_db_recovery.rs index 89bb16643c..fb5a1ad165 100644 --- a/codex-rs/cli/src/state_db_recovery.rs +++ b/codex-rs/cli/src/state_db_recovery.rs @@ -21,6 +21,10 @@ pub(crate) fn is_corruption(detail: &str) -> bool { codex_state::sqlite_error_detail_is_corruption(detail) } +pub(crate) fn is_migration_incompatible(detail: &str) -> bool { + codex_state::sqlite_error_detail_is_migration_incompatible(detail) +} + pub(crate) fn is_auto_backup_recoverable(startup_error: &LocalStateDbStartupError) -> bool { is_corruption(startup_error.detail()) || sqlite_home_is_blocking_file(startup_error) } @@ -71,8 +75,15 @@ pub(crate) fn confirm_fresh_start_rebuild( } pub(crate) fn print_diagnostic_guidance(startup_error: &LocalStateDbStartupError) { - eprintln!("Codex couldn't start because its local database appears to be damaged."); - eprintln!("Run `codex doctor` to check your setup and get next-step guidance."); + if is_migration_incompatible(startup_error.detail()) { + eprintln!( + "Codex couldn't start because its local database migration history is incompatible with this version." + ); + eprintln!("Run `codex doctor --fix` to back up and rebuild the affected database."); + } else { + eprintln!("Codex couldn't start because its local database appears to be damaged."); + eprintln!("Run `codex doctor` to check your setup and get next-step guidance."); + } eprintln!("If this keeps happening, share the technical details below when asking for help."); print_technical_details(startup_error); } diff --git a/codex-rs/state/src/lib.rs b/codex-rs/state/src/lib.rs index 4b8e3ec3f5..48c80ba256 100644 --- a/codex-rs/state/src/lib.rs +++ b/codex-rs/state/src/lib.rs @@ -12,6 +12,7 @@ const _: () = assert!( mod audit; mod extract; pub mod log_db; +mod migration_diagnostics; mod migrations; mod model; mod paths; @@ -32,6 +33,10 @@ pub use audit::read_thread_state_audit_rows; /// Most consumers should prefer [`StateRuntime`]. pub use extract::apply_rollout_item; pub use extract::rollout_item_affects_thread_metadata; +pub use migration_diagnostics::RuntimeDbMigrationInspection; +pub use migration_diagnostics::RuntimeDbMigrationIssue; +pub use migration_diagnostics::RuntimeDbMigrationStatus; +pub use migration_diagnostics::inspect_runtime_db_migrations; pub use model::AgentJob; pub use model::AgentJobCreateParams; pub use model::AgentJobItem; @@ -74,9 +79,11 @@ pub use runtime::logs_db_path; pub use runtime::memories_db_filename; pub use runtime::memories_db_path; pub use runtime::runtime_db_path_for_corruption_error; +pub use runtime::runtime_db_path_for_init_error; pub use runtime::runtime_db_paths; pub use runtime::sqlite_error_detail_is_corruption; pub use runtime::sqlite_error_detail_is_lock; +pub use runtime::sqlite_error_detail_is_migration_incompatible; pub use runtime::sqlite_integrity_check; pub use runtime::state_db_filename; pub use runtime::state_db_path; diff --git a/codex-rs/state/src/migration_diagnostics.rs b/codex-rs/state/src/migration_diagnostics.rs new file mode 100644 index 0000000000..055798b6e7 --- /dev/null +++ b/codex-rs/state/src/migration_diagnostics.rs @@ -0,0 +1,175 @@ +//! Read-only inspection of SQLx migration metadata for runtime databases. + +use std::path::Path; +use std::path::PathBuf; + +use sqlx::Row; +use sqlx::migrate::Migrator; +use sqlx::sqlite::SqliteConnectOptions; +use sqlx::sqlite::SqlitePoolOptions; + +use crate::migrations::runtime_goals_migrator; +use crate::migrations::runtime_logs_migrator; +use crate::migrations::runtime_memories_migrator; +use crate::migrations::runtime_state_migrator; +use crate::runtime::goals_db_path; +use crate::runtime::logs_db_path; +use crate::runtime::memories_db_path; +use crate::runtime::state_db_path; + +/// Migration compatibility for one Codex runtime database. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct RuntimeDbMigrationInspection { + pub label: &'static str, + pub path: PathBuf, + pub status: RuntimeDbMigrationStatus, +} + +/// Read-only compatibility status for a runtime database's migration ledger. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum RuntimeDbMigrationStatus { + Missing, + Compatible { applied: usize, pending: usize }, + Incompatible(Vec), + Unreadable(String), +} + +/// An applied migration state that the current runtime cannot safely use. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum RuntimeDbMigrationIssue { + Dirty { version: i64 }, + ChecksumMismatch { version: i64 }, +} + +struct RuntimeDbMigrationSpec { + label: &'static str, + path: PathBuf, + migrator: Migrator, +} + +/// Inspect every runtime database without applying pending migrations. +pub async fn inspect_runtime_db_migrations( + sqlite_home: &Path, +) -> Vec { + let specs = [ + RuntimeDbMigrationSpec { + label: "state DB", + path: state_db_path(sqlite_home), + migrator: runtime_state_migrator(), + }, + RuntimeDbMigrationSpec { + label: "log DB", + path: logs_db_path(sqlite_home), + migrator: runtime_logs_migrator(), + }, + RuntimeDbMigrationSpec { + label: "goals DB", + path: goals_db_path(sqlite_home), + migrator: runtime_goals_migrator(), + }, + RuntimeDbMigrationSpec { + label: "memories DB", + path: memories_db_path(sqlite_home), + migrator: runtime_memories_migrator(), + }, + ]; + + let mut inspections = Vec::with_capacity(specs.len()); + for spec in specs { + inspections.push(inspect_runtime_db_migration(spec).await); + } + inspections +} + +async fn inspect_runtime_db_migration( + spec: RuntimeDbMigrationSpec, +) -> RuntimeDbMigrationInspection { + if !spec.path.is_file() { + return RuntimeDbMigrationInspection { + label: spec.label, + path: spec.path, + status: RuntimeDbMigrationStatus::Missing, + }; + } + + let status = match inspect_existing_database(&spec.path, &spec.migrator).await { + Ok(status) => status, + Err(err) => RuntimeDbMigrationStatus::Unreadable(err.to_string()), + }; + RuntimeDbMigrationInspection { + label: spec.label, + path: spec.path, + status, + } +} + +async fn inspect_existing_database( + path: &Path, + migrator: &Migrator, +) -> anyhow::Result { + let options = SqliteConnectOptions::new() + .filename(path) + .create_if_missing(false) + .read_only(true); + let pool = SqlitePoolOptions::new() + .max_connections(1) + .connect_with(options) + .await?; + let table_exists = sqlx::query_scalar::<_, i64>( + "SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name = '_sqlx_migrations'", + ) + .fetch_one(&pool) + .await? + > 0; + if !table_exists { + pool.close().await; + return Ok(RuntimeDbMigrationStatus::Compatible { + applied: 0, + pending: migrator.iter().count(), + }); + } + + let rows = sqlx::query("SELECT version, success, checksum FROM _sqlx_migrations") + .fetch_all(&pool) + .await?; + pool.close().await; + + let mut applied_versions = Vec::with_capacity(rows.len()); + let mut issues = Vec::new(); + for row in &rows { + let version = row.try_get::("version")?; + applied_versions.push(version); + if !row.try_get::("success")? { + issues.push(RuntimeDbMigrationIssue::Dirty { version }); + continue; + } + let Some(migration) = migrator + .iter() + .find(|migration| migration.version == version) + else { + // Runtime migrators intentionally tolerate migrations from a newer binary. + continue; + }; + let checksum = row.try_get::, _>("checksum")?; + if checksum.as_slice() != migration.checksum.as_ref() { + issues.push(RuntimeDbMigrationIssue::ChecksumMismatch { version }); + } + } + + if !issues.is_empty() { + return Ok(RuntimeDbMigrationStatus::Incompatible(issues)); + } + + let pending = migrator + .iter() + .filter(|migration| !applied_versions.contains(&migration.version)) + .count(); + Ok(RuntimeDbMigrationStatus::Compatible { + applied: rows.len(), + pending, + }) +} + +#[cfg(test)] +#[path = "migration_diagnostics_tests.rs"] +mod tests; diff --git a/codex-rs/state/src/migration_diagnostics_tests.rs b/codex-rs/state/src/migration_diagnostics_tests.rs new file mode 100644 index 0000000000..700679ee5a --- /dev/null +++ b/codex-rs/state/src/migration_diagnostics_tests.rs @@ -0,0 +1,143 @@ +use std::path::Path; + +use pretty_assertions::assert_eq; +use sqlx::SqlitePool; +use sqlx::sqlite::SqliteConnectOptions; + +use super::*; +use crate::StateRuntime; +use crate::migrations::STATE_MIGRATOR; +use crate::runtime::test_support::unique_temp_dir; + +async fn state_inspection(sqlite_home: &Path) -> RuntimeDbMigrationInspection { + inspect_runtime_db_migrations(sqlite_home) + .await + .into_iter() + .find(|inspection| inspection.label == "state DB") + .expect("state inspection") +} + +async fn state_pool(sqlite_home: &Path) -> SqlitePool { + SqlitePool::connect_with( + SqliteConnectOptions::new() + .filename(state_db_path(sqlite_home)) + .create_if_missing(false), + ) + .await + .expect("state pool") +} + +#[tokio::test] +async fn missing_runtime_databases_are_reported_without_creation() { + let sqlite_home = unique_temp_dir(); + + let inspections = inspect_runtime_db_migrations(&sqlite_home).await; + + assert_eq!(inspections.len(), 4); + assert!( + inspections + .iter() + .all(|inspection| inspection.status == RuntimeDbMigrationStatus::Missing) + ); + assert!(!sqlite_home.exists()); +} + +#[tokio::test] +async fn current_runtime_database_is_compatible() { + let sqlite_home = unique_temp_dir(); + let runtime = StateRuntime::init(sqlite_home.clone(), "test-provider".to_string()) + .await + .expect("runtime"); + runtime.close().await; + + let inspection = state_inspection(&sqlite_home).await; + + assert_eq!( + inspection.status, + RuntimeDbMigrationStatus::Compatible { + applied: STATE_MIGRATOR.iter().count(), + pending: 0, + } + ); +} + +#[tokio::test] +async fn changed_checksum_is_incompatible() { + let sqlite_home = unique_temp_dir(); + let runtime = StateRuntime::init(sqlite_home.clone(), "test-provider".to_string()) + .await + .expect("runtime"); + runtime.close().await; + let pool = state_pool(&sqlite_home).await; + sqlx::query("UPDATE _sqlx_migrations SET checksum = ? WHERE version = 36") + .bind(vec![0_u8; 48]) + .execute(&pool) + .await + .expect("change checksum"); + pool.close().await; + + let inspection = state_inspection(&sqlite_home).await; + + assert_eq!( + inspection.status, + RuntimeDbMigrationStatus::Incompatible(vec![RuntimeDbMigrationIssue::ChecksumMismatch { + version: 36 + }]) + ); +} + +#[tokio::test] +async fn dirty_migration_is_incompatible() { + let sqlite_home = unique_temp_dir(); + let runtime = StateRuntime::init(sqlite_home.clone(), "test-provider".to_string()) + .await + .expect("runtime"); + runtime.close().await; + let pool = state_pool(&sqlite_home).await; + sqlx::query("UPDATE _sqlx_migrations SET success = FALSE WHERE version = 36") + .execute(&pool) + .await + .expect("mark dirty"); + pool.close().await; + + let inspection = state_inspection(&sqlite_home).await; + + assert_eq!( + inspection.status, + RuntimeDbMigrationStatus::Incompatible(vec![RuntimeDbMigrationIssue::Dirty { + version: 36, + }]) + ); +} + +#[tokio::test] +async fn future_migration_is_tolerated() { + let sqlite_home = unique_temp_dir(); + let runtime = StateRuntime::init(sqlite_home.clone(), "test-provider".to_string()) + .await + .expect("runtime"); + runtime.close().await; + let pool = state_pool(&sqlite_home).await; + sqlx::query( + "INSERT INTO _sqlx_migrations (version, description, success, checksum, execution_time) VALUES (?, ?, ?, ?, ?)", + ) + .bind(/*value*/ 9_999_i64) + .bind("future migration") + .bind(/*value*/ true) + .bind(vec![1_u8, 2, 3, 4]) + .bind(/*value*/ 1_i64) + .execute(&pool) + .await + .expect("insert future migration"); + pool.close().await; + + let inspection = state_inspection(&sqlite_home).await; + + assert_eq!( + inspection.status, + RuntimeDbMigrationStatus::Compatible { + applied: STATE_MIGRATOR.iter().count() + 1, + pending: 0, + } + ); +} diff --git a/codex-rs/state/src/runtime.rs b/codex-rs/state/src/runtime.rs index 2937bf0c2e..245ed00def 100644 --- a/codex-rs/state/src/runtime.rs +++ b/codex-rs/state/src/runtime.rs @@ -65,7 +65,7 @@ mod memories; mod recovery; mod remote_control; #[cfg(test)] -mod test_support; +pub(crate) mod test_support; mod threads; pub use goals::GoalAccountingMode; @@ -77,8 +77,10 @@ pub use recovery::RuntimeDbBackup; pub use recovery::backup_runtime_db_for_fresh_start; pub use recovery::is_sqlite_corruption_error; pub use recovery::runtime_db_path_for_corruption_error; +pub use recovery::runtime_db_path_for_init_error; pub use recovery::sqlite_error_detail_is_corruption; pub use recovery::sqlite_error_detail_is_lock; +pub use recovery::sqlite_error_detail_is_migration_incompatible; pub use remote_control::RemoteControlEnrollmentRecord; pub use threads::ThreadFilterOptions; diff --git a/codex-rs/state/src/runtime/recovery.rs b/codex-rs/state/src/runtime/recovery.rs index d9cf0bcdc9..cb7a497bab 100644 --- a/codex-rs/state/src/runtime/recovery.rs +++ b/codex-rs/state/src/runtime/recovery.rs @@ -95,6 +95,11 @@ pub fn runtime_db_path_for_corruption_error(err: &anyhow::Error) -> Option Option { err.chain() .find_map(|source| source.downcast_ref::()) .map(|err| err.path().to_path_buf()) @@ -141,6 +146,13 @@ pub fn sqlite_error_detail_is_lock(detail: &str) -> bool { detail.contains("database is locked") || detail.contains("database is busy") } +pub fn sqlite_error_detail_is_migration_incompatible(detail: &str) -> bool { + let detail = detail.to_ascii_lowercase(); + (detail.contains("migration ") + && detail.contains("was previously applied but has been modified")) + || (detail.contains("migration ") && detail.contains("is partially applied")) +} + async fn backup_runtime_db_files(db_path: &Path) -> std::io::Result> { let sqlite_home = db_path.parent().ok_or_else(|| { std::io::Error::other(format!( diff --git a/codex-rs/state/src/runtime/recovery_tests.rs b/codex-rs/state/src/runtime/recovery_tests.rs index 7424dbcfe1..d67258854c 100644 --- a/codex-rs/state/src/runtime/recovery_tests.rs +++ b/codex-rs/state/src/runtime/recovery_tests.rs @@ -72,6 +72,12 @@ fn sqlite_error_detail_classifies_corruption_and_lock_errors() { assert!(!sqlite_error_detail_is_corruption("database is locked")); assert!(sqlite_error_detail_is_lock("database is locked")); assert!(sqlite_error_detail_is_lock("database is busy")); + assert!(sqlite_error_detail_is_migration_incompatible( + "migration 36 was previously applied but has been modified" + )); + assert!(sqlite_error_detail_is_migration_incompatible( + "migration 12 is partially applied; fix and remove row" + )); } #[tokio::test] diff --git a/codex-rs/state/src/runtime/test_support.rs b/codex-rs/state/src/runtime/test_support.rs index 848a193335..5771767d84 100644 --- a/codex-rs/state/src/runtime/test_support.rs +++ b/codex-rs/state/src/runtime/test_support.rs @@ -25,7 +25,7 @@ use uuid::Uuid; use crate::ThreadMetadata; #[cfg(test)] -pub(super) fn unique_temp_dir() -> PathBuf { +pub(crate) fn unique_temp_dir() -> PathBuf { let nanos = SystemTime::now() .duration_since(UNIX_EPOCH) .map_or(0, |duration| duration.as_nanos()); diff --git a/codex-rs/tui/src/lib.rs b/codex-rs/tui/src/lib.rs index 3ec8bef7c0..307e222bba 100644 --- a/codex-rs/tui/src/lib.rs +++ b/codex-rs/tui/src/lib.rs @@ -284,7 +284,7 @@ async fn init_state_db_for_app_server_target( ) -> std::io::Result> { match app_server_target { AppServerTarget::Embedded => state_db::try_init(config).await.map(Some).map_err(|err| { - let database_path = codex_state::runtime_db_path_for_corruption_error(&err) + let database_path = codex_state::runtime_db_path_for_init_error(&err) .unwrap_or_else(|| codex_state::state_db_path(config.sqlite_home.as_path())); std::io::Error::other(LocalStateDbStartupError::new( database_path,