okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
e3168a0
main
1package daemon 2 3import ( 4"context" 5"io" 6"net/http" 7 8"albedo/cli/internal/daemon/protocol" 9) 10 11type CapabilityCatalog struct { 12Workspace ,Revision string 13Extensions map [string ]bool 14Diagnostics []string 15Candidates []CatalogCandidate 16Commands []SessionCommand 17Pages []* PageDocument 18} 19type CatalogCandidate struct { 20Description ,ResolvedSource ,PreferenceKey ,Diagnostic ,ShadowedBy * string 21GlobalPreference ,SessionOverride * bool 22ID ,Kind ,Title ,Source string 23Valid ,EffectiveEnabled ,Eligible ,Quarantined bool 24Dependencies []string 25Extension * protocol.ExtensionMetadata 26} 27type CatalogCapabilityRequest struct { 28Revision ,ID ,Kind ,Scope ,ETag string 29Enabled * bool 30} 31 32type CatalogDiscoveryError struct {Code ,Detail string } 33 34func (e * CatalogDiscoveryError )Error ()string {return e .Detail } 35 36func GetCapabilityCatalog (ctx context.Context ,conn * Connection ,session string ) (CapabilityCatalog ,error ) { 37return readCapabilityCatalog (ctx ,conn ,session ,true ) 38} 39 40func readCapabilityCatalog (ctx context.Context ,conn * Connection ,session string ,withDiscovery bool ) (CapabilityCatalog ,error ) { 41var result CapabilityCatalog 42result .Extensions = map [string ]bool {} 43result .Candidates = []CatalogCandidate {} 44result .Commands = []SessionCommand {} 45params := protocol.GetCatalogParams {Limit :new (int64 (200 ))} 46first := true 47seenCandidates ,seenCommands ,seenTokens := map [string ]bool {},map [string ]bool {},map [string ]bool {} 48pending := []string {} 49var loadedRevision * string 50loadedSeen := false 51for { 52var catalog protocol.Catalog 53err := executeRead (ctx ,conn ,operation {Capability :"catalog" ,Name :"read session catalog" ,BuildRequest :func (base string ,body io.Reader ) (* http.Request ,error ) { 54return protocol .NewGetCatalogRequest (base ,session ,& params ) 55 },Policy :readRecovery },func (data []byte )error { 56return decodeRequired (data ,& catalog ) 57 }) 58if err != nil { 59return CapabilityCatalog {},err 60 } 61if catalog .Loaded .Commands == nil || (catalog .Discovery == nil )!= (catalog .DiscoveryFailure != nil ) { 62return CapabilityCatalog {},fieldError ("catalog" ) 63 } 64if catalog .DiscoveryFailure != nil { 65if catalog .DiscoveryFailure .Code == "" || catalog .DiscoveryFailure .Detail == "" { 66return CapabilityCatalog {},fieldError ("catalog discovery failure" ) 67 } 68if withDiscovery { 69return CapabilityCatalog {},& CatalogDiscoveryError {Code :catalog .DiscoveryFailure .Code ,Detail :catalog .DiscoveryFailure .Detail } 70 } 71 } 72if withDiscovery { 73if catalog .Discovery .Revision == "" || catalog .Discovery .Candidates == nil { 74return CapabilityCatalog {},fieldError ("catalog discovery" ) 75 } 76if first { 77result .Workspace ,result .Revision = catalog .Discovery .Workspace ,catalog .Discovery .Revision 78first = false 79 }else if result .Revision != catalog .Discovery .Revision { 80return CapabilityCatalog {},& APIError {StatusCode :409 ,Code :"catalog_changed" ,Message :"the catalog changed during paging; refresh it" } 81 } 82 } 83if ! loadedSeen { 84loadedRevision ,loadedSeen = catalog .Loaded .Revision ,true 85 }else if (loadedRevision == nil )!= (catalog .Loaded .Revision == nil )|| value (loadedRevision )!= value (catalog .Loaded .Revision ) { 86return CapabilityCatalog {},fieldError ("loaded catalog revision" ) 87 } 88if withDiscovery { 89for _ ,candidate := range catalog .Discovery .Candidates { 90if seenCandidates [candidate .ID ] { 91continue 92 } 93seenCandidates [candidate .ID ]= true 94description := candidate .Description 95item := CatalogCandidate {ID :candidate .ID ,Kind :catalogKind (candidate .Kind ),Title :candidate .Title ,Source :candidate .Source ,Description :& description ,ResolvedSource :candidate .ResolvedSource ,PreferenceKey :candidate .PreferenceKey ,Diagnostic :nil ,ShadowedBy :candidate .ShadowedBy ,GlobalPreference :candidate .GlobalPreference ,SessionOverride :candidate .SessionOverride ,Valid :candidate .Valid ,EffectiveEnabled :candidate .EffectiveEnabled ,Eligible :candidate .Eligible ,Quarantined :candidate .Quarantined ,Dependencies :candidate .Dependencies ,Extension :candidate .Extension } 96if candidate .Diagnostic != nil { 97detail := candidate .Diagnostic .Detail 98item .Diagnostic = & detail 99 } 100if candidate .Kind == "extension" { 101result .Extensions [candidate .ID ]= candidate .EffectiveEnabled 102 } 103result .Candidates = append (result .Candidates ,item ) 104 } 105for _ ,reason := range catalog .Discovery .Diagnostics { 106result .Diagnostics = append (result .Diagnostics ,reason .Detail ) 107 } 108 } 109commands := make ([]SessionCommand ,0 ,len (catalog .Loaded .Commands )+ len (catalog .NativeCommands )) 110if catalog .Loaded .Revision == nil { 111for _ ,declared := range catalog .NativeCommands { 112command ,err := sessionCommandValue (declared ,"" ) 113if err != nil { 114return CapabilityCatalog {},err 115 } 116commands = append (commands ,command ) 117 } 118 } 119for _ ,raw := range catalog .Loaded .Commands { 120command ,err := decodeSessionCommand (raw ) 121if err != nil { 122return CapabilityCatalog {},err 123 } 124commands = append (commands ,command ) 125 } 126for _ ,command := range commands { 127if ! seenCommands [command .ID ] { 128seenCommands [command .ID ]= true 129result .Commands = append (result .Commands ,command ) 130 } 131 } 132for _ ,page := range catalog .Pages { 133converted ,err := pageValue (page ) 134if err != nil { 135return CapabilityCatalog {},err 136 } 137result .Pages = append (result .Pages ,converted ) 138 } 139nextPages := []* string {catalog .Loaded .Next } 140if withDiscovery { 141nextPages = append (nextPages ,catalog .Discovery .Next ) 142 } 143for _ ,next := range nextPages { 144if next != nil && ! seenTokens [* next ] { 145seenTokens [* next ]= true 146pending = append (pending ,* next ) 147 } 148 } 149if len (pending )== 0 { 150break 151 } 152params .Next = new (pending [0 ]) 153pending = pending [1 :] 154 } 155return result ,nil 156} 157func SetCatalogCapability (ctx context.Context ,conn * Connection ,session string ,request CatalogCapabilityRequest ) (ReloadResult ,error ) { 158return setSelection (ctx ,conn ,session ,request .Kind ,request .ID ,request .Revision ,request .Scope ,request .ETag ,request .Enabled ) 159} 160 161func catalogKind (kind string )string { 162switch kind { 163case "extension" : 164return "extensions" 165case "skill" : 166return "skills" 167case "instruction" : 168return "instructions" 169 } 170return kind 171}