okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
96704f7
main
1package tui 2 3import ( 4"albedo/cli/internal/config" 5"albedo/cli/internal/daemon" 6"errors" 7 8 tea"charm.land/bubbletea/v2" 9) 10 11// The capability pages' screenshot states: each page's list, filter, odd 12// rows, confirmations, saves, forms, and load outcomes. 13func init () { 14enter := tea.KeyPressMsg {Code :tea .KeyEnter } 15shiftEnter := tea.KeyPressMsg {Code :tea .KeyEnter ,Mod :tea .ModShift } 16down := tea.KeyPressMsg {Code :tea .KeyDown } 17chord := func (r rune ) tea.Msg {return tea.KeyPressMsg {Code :r ,Mod :tea .ModCtrl } } 18typed := func (text string ) []tea.Msg { 19var keys []tea.Msg 20for _ ,r := range text { 21keys = append (keys , tea.KeyPressMsg {Code :r ,Text :string (r )}) 22 } 23return keys 24 } 25saveFailed := func (kind string ,items []capabilityItem ,keys ... tea.Msg )func (int ,int )string { 26return func (w ,h int )string { 27m := capsModel (kind ,w ,h ,items ,true ,nil ,keys ... ) 28m ,_ = m .Update (capabilitySavedMsg {Gen :m .Generation ,Err :errors .New ("daemon refused the change" )}) 29return m .View () 30 } 31 } 32skills := capsSkills () 33servers := capsServers () 34registerShots ("caps" , 35shotState {"skills-list" ,capsShot ("skills" ,skills ,true ,capsDiagnostics )}, 36shotState {"skills-cursor-overridden" ,capsShot ("skills" ,skills ,true ,nil ,down )}, 37shotState {"skills-cursor-shadowed" ,capsShot ("skills" ,skills ,true ,nil ,down ,down ,down )}, 38shotState {"skills-cursor-invalid" ,capsShot ("skills" ,skills ,true ,nil ,down ,down ,down ,down )}, 39shotState {"skills-filtering" ,capsShot ("skills" ,skills ,true ,nil ,typed ("notes" )... )}, 40shotState {"skills-no-match" ,capsShot ("skills" ,skills ,true ,nil ,typed ("zzz" )... )}, 41shotState {"skills-confirm-global" ,capsShot ("skills" ,skills ,true ,nil ,enter )}, 42shotState {"skills-confirm-session" ,capsShot ("skills" ,skills ,true ,nil ,shiftEnter )}, 43shotState {"skills-confirm-follow-global" ,capsShot ("skills" ,skills ,true ,nil ,down ,chord ('x' ))}, 44shotState {"skills-saving" ,capsShot ("skills" ,skills ,true ,nil ,shiftEnter ,enter )}, 45shotState {"skills-save-failed" ,saveFailed ("skills" ,skills ,shiftEnter ,enter )}, 46shotState {"skills-extension-off" ,capsShot ("skills" ,skills ,false ,nil )}, 47shotState {"skills-confirm-extension" ,capsShot ("skills" ,skills ,false ,nil ,chord ('t' ))}, 48shotState {"skills-notice" ,func (w ,h int )string { 49m := capsModel ("skills" ,w ,h ,skills ,true ,nil ) 50m .Notice = "Saved. Reload the session to apply the selection." 51return m .View () 52 }}, 53shotState {"skills-loading" ,func (w ,h int )string { 54m := NewCapabilityPageModel (nil ,"s" ,"skills" ) 55m .SetSize (w ,h ) 56return m .View () 57 }}, 58shotState {"skills-empty" ,capsShot ("skills" ,nil ,true ,nil )}, 59shotState {"skills-load-failed" ,func (w ,h int )string { 60m := NewCapabilityPageModel (nil ,"s" ,"skills" ) 61m .SetSize (w ,h ) 62m ,_ = m .Update (capabilityLoadedMsg {Gen :m .Generation ,Err :errors .New ("daemon connection unavailable" )}) 63return m .View () 64 }}, 65shotState {"instructions-list" ,capsShot ("instructions" ,capsInstructions (),true ,nil )}, 66shotState {"mcp-list" ,capsShot ("mcp" ,servers ,true ,nil )}, 67shotState {"mcp-cursor-disabled" ,capsShot ("mcp" ,servers ,true ,nil ,down )}, 68shotState {"mcp-filtering" ,capsShot ("mcp" ,servers ,true ,nil ,typed ("fil" )... )}, 69shotState {"mcp-no-match" ,capsShot ("mcp" ,servers ,true ,nil ,typed ("zzz" )... )}, 70shotState {"mcp-confirm-global" ,capsShot ("mcp" ,servers ,true ,nil ,enter )}, 71shotState {"mcp-confirm-session" ,capsShot ("mcp" ,servers ,true ,nil ,shiftEnter )}, 72shotState {"mcp-enable-server" ,capsShot ("mcp" ,servers ,true ,nil ,down ,chord ('g' ))}, 73shotState {"mcp-form-add" ,capsShot ("mcp" ,servers ,true ,nil ,chord ('o' ))}, 74shotState {"mcp-form-add-typed" ,capsShot ("mcp" ,servers ,true ,nil ,chord ('o' ), tea.KeyPressMsg {Code :tea .KeyExtended ,Text :"http://127.0.0.1:9/mcp" })}, 75shotState {"mcp-form-invalid" ,capsShot ("mcp" ,servers ,true ,nil ,chord ('o' ),chord ('s' ))}, 76shotState {"mcp-form-edit" ,capsShot ("mcp" ,servers ,true ,nil ,chord ('e' ))}, 77shotState {"mcp-form-saving" ,func (w ,h int )string { 78m := capsModel ("mcp" ,w ,h ,servers ,true ,nil ,chord ('o' ), tea.KeyPressMsg {Code :tea .KeyExtended ,Text :"http://127.0.0.1:9/mcp" },chord ('s' )) 79return m .View () 80 }}, 81shotState {"mcp-form-save-failed" ,saveFailed ("mcp" ,servers ,chord ('o' ), tea.KeyPressMsg {Code :tea .KeyExtended ,Text :"http://127.0.0.1:9/mcp" },chord ('s' ))}, 82shotState {"mcp-confirm-delete" ,capsShot ("mcp" ,servers ,true ,nil ,chord ('d' ))}, 83shotState {"mcp-delete-save-failed" ,saveFailed ("mcp" ,servers ,chord ('d' ),enter )}, 84shotState {"mcp-confirm-extension" ,capsShot ("mcp" ,servers ,false ,nil ,chord ('t' ))}, 85shotState {"mcp-extension-off" ,capsShot ("mcp" ,servers ,false ,nil )}, 86shotState {"mcp-empty" ,capsShot ("mcp" ,nil ,true ,nil )}, 87 ) 88} 89 90// capsModel is a loaded page of one kind with keys pressed on it. 91func capsModel (kind string ,width ,height int ,items []capabilityItem ,extension bool ,diagnostics []string ,keys ... tea.Msg )CapabilityPageModel { 92m := NewCapabilityPageModel (nil ,"s" ,kind ) 93m .SetSize (width ,height ) 94m ,_ = m .Update (capabilityLoadedMsg {Gen :m .Generation ,ExtensionEnabled :extension ,Revision :"rev" ,Diagnostics :diagnostics ,Items :items }) 95for _ ,key := range keys { 96m ,_ = m .Update (key ) 97 } 98return m 99} 100 101func capsShot (kind string ,items []capabilityItem ,extension bool ,diagnostics []string ,keys ... tea.Msg )func (int ,int )string { 102return func (width ,height int )string { 103return capsModel (kind ,width ,height ,items ,extension ,diagnostics ,keys ... ).View () 104 } 105} 106 107var capsDiagnostics = []string {"skipped one unreadable directory: ~/.agents/skills/old" } 108 109func capsSkills () []capabilityItem { 110key := "draft" 111on ,off := true ,false 112return []capabilityItem { 113 {ID :"enable-review" ,Title :"enable-review" ,Candidate : daemon.CatalogCandidate {ID :"enable-review" ,Source :"/work/.agents/skills/enable-review/SKILL.md" ,Description :new ("verify enabling the skills extension "),PreferenceKey :& key ,Valid :true ,EffectiveEnabled :true ,Eligible :true ,GlobalPreference :& on }}, 114 {ID :"lint-rules" ,Title :"lint-rules" ,Candidate : daemon.CatalogCandidate {ID :"lint-rules" ,Source :"/home/dawn/.agents/skills/lint-rules/SKILL.md" ,Description :new ("house lint rules for go ,kept quiet on generated code "),PreferenceKey :& key ,Valid :true ,GlobalPreference :& on ,SessionOverride :& off ,Eligible :false }}, 115 {ID :"release-notes" ,Title :"release-notes" ,Candidate : daemon.CatalogCandidate {ID :"release-notes" ,Source :"/home/dawn/.agents/skills/release-notes/SKILL.md" ,Description :new ("draft changelog entries from commits "),PreferenceKey :& key ,Valid :true ,GlobalPreference :& off ,SessionOverride :& on ,EffectiveEnabled :true ,Eligible :true }}, 116 {ID :"tangled" ,Title :"tangled" ,Candidate : daemon.CatalogCandidate {ID :"tangled" ,Source :"/home/dawn/.agents/skills/tangled/SKILL.md" ,Description :new ("tg cli for tangled tasks "),PreferenceKey :& key ,Valid :true ,ShadowedBy :new ("tangled - local "),GlobalPreference :& on }}, 117 {ID :"broken" ,Title :"broken" ,Candidate : daemon.CatalogCandidate {ID :"broken" ,Source :"/work/.agents/skills/broken/SKILL.md" ,Description :new ("missing frontmatter "),Valid :false ,Diagnostic :new ("frontmatter has no name ")}}, 118 } 119} 120 121func capsInstructions () []capabilityItem { 122key := "agents" 123on := true 124return []capabilityItem { 125 {ID :"AGENTS.md" ,Title :"AGENTS.md" ,Candidate : daemon.CatalogCandidate {ID :"AGENTS.md" ,Source :"/work/AGENTS.md" ,Description :new ("workspace conventions "),PreferenceKey :& key ,Valid :true ,GlobalPreference :& on ,EffectiveEnabled :true ,Eligible :true }}, 126 {ID :"CLAUDE.md" ,Title :"CLAUDE.md" ,Candidate : daemon.CatalogCandidate {ID :"CLAUDE.md" ,Source :"/home/dawn/.claude/CLAUDE.md" ,Description :new ("personal notes , shadowedby AGENTS .md "),PreferenceKey :& key ,Valid :true ,ShadowedBy :new ("AGENTS.md" )}}, 127 } 128} 129 130func capsServers () []capabilityItem { 131on ,off := true ,false 132return []capabilityItem { 133 {ID :"docs" ,Title :"docs" ,Detail :"http · https://docs.example/mcp" ,Server : config.MCPServer {Type :"http" ,URL :"https://docs.example/mcp" ,Enabled :& on ,StartupTimeoutMs :8000 },Secrets : daemon.MCPSecretNames {BearerToken :true ,Headers : []string {"X-Team" }}}, 134 {ID :"filesystem" ,Title :"filesystem" ,Detail :"stdio · npx" ,Server : config.MCPServer {Type :"stdio" ,Command :"npx" ,Args : []string {"-y" ,"@modelcontextprotocol/server-filesystem" ,"/tmp/notes" },Enabled :& off ,EnabledTools : []string {"read_file" }}}, 135 {ID :"local" ,Title :"local" ,Detail :"http · http://127.0.0.1:8787/mcp" ,Server : config.MCPServer {Type :"http" ,URL :"http://127.0.0.1:8787/mcp" }}, 136 } 137}