77 tea "github.com/charmbracelet/bubbletea"
88 "github.com/charmbracelet/lipgloss"
99 "github.com/agentsdance/agentx/internal/agent"
10+ "github.com/agentsdance/agentx/internal/skills"
1011 "github.com/agentsdance/agentx/ui/components"
1112 "github.com/agentsdance/agentx/ui/theme"
1213)
@@ -18,14 +19,39 @@ type AvailableSkill struct {
1819 Source string // GitHub tree URL or repo#fragment
1920}
2021
21- // Available skills from anthropics/skills repository
22- var AvailableSkills = []AvailableSkill {
23- {Name : "frontend-design" , Description : "Production-grade UI design" , Source : "https://github.com/anthropics/skills/tree/main/skills/frontend-design" },
24- {Name : "mcp-builder" , Description : "Build MCP servers" , Source : "https://github.com/anthropics/skills/tree/main/skills/mcp-builder" },
25- {Name : "pdf" , Description : "PDF document handling" , Source : "https://github.com/anthropics/skills/tree/main/skills/pdf" },
26- {Name : "docx" , Description : "Word document handling" , Source : "https://github.com/anthropics/skills/tree/main/skills/docx" },
27- {Name : "xlsx" , Description : "Excel spreadsheet handling" , Source : "https://github.com/anthropics/skills/tree/main/skills/xlsx" },
28- {Name : "pptx" , Description : "PowerPoint handling" , Source : "https://github.com/anthropics/skills/tree/main/skills/pptx" },
22+ // AvailableSkills is the list of skills from the registry
23+ var AvailableSkills []AvailableSkill
24+
25+ // InitAvailableSkills fetches skills from the registry
26+ func InitAvailableSkills () {
27+ registrySkills , err := skills .FetchSkillsRegistryWithFallback ()
28+ if err != nil {
29+ // Use empty list if fetch fails
30+ AvailableSkills = []AvailableSkill {}
31+ return
32+ }
33+
34+ AvailableSkills = make ([]AvailableSkill , len (registrySkills ))
35+ for i , s := range registrySkills {
36+ // Convert source to installation URL
37+ source := s .Source
38+ if source == "local" {
39+ // For local skills in agentsdance/agentskills repo
40+ source = fmt .Sprintf ("https://github.com/agentsdance/agentskills/tree/master/skills/%s" , s .Name )
41+ }
42+
43+ // Truncate description for display
44+ desc := s .Description
45+ if len (desc ) > 40 {
46+ desc = desc [:37 ] + "..."
47+ }
48+
49+ AvailableSkills [i ] = AvailableSkill {
50+ Name : s .Name ,
51+ Description : desc ,
52+ Source : source ,
53+ }
54+ }
2955}
3056
3157// AgentSkillStatus represents an agent's skill installation status
@@ -49,6 +75,9 @@ type SkillsView struct {
4975
5076// NewSkillsView creates a new skills view
5177func NewSkillsView () * SkillsView {
78+ // Initialize available skills from registry
79+ InitAvailableSkills ()
80+
5281 agents := agent .GetAllAgents ()
5382 statuses := make ([]AgentSkillStatus , len (agents ))
5483
@@ -111,12 +140,22 @@ func (v *SkillsView) Update(msg tea.Msg) (View, tea.Cmd) {
111140 case "c" :
112141 v .refreshStatus ()
113142 v .message = "Status refreshed"
143+ case "R" :
144+ // Force refresh skills from registry
145+ InitAvailableSkills ()
146+ v .refreshStatus ()
147+ v .message = fmt .Sprintf ("Refreshed %d skills from registry" , len (AvailableSkills ))
114148 }
115149 }
116150 return v , nil
117151}
118152
119153func (v * SkillsView ) installSelected () {
154+ if len (AvailableSkills ) == 0 {
155+ v .message = "No skills available"
156+ return
157+ }
158+
120159 status := & v .agents [v .cursorCol ]
121160 agentName := status .Agent .Name ()
122161 skill := AvailableSkills [v .cursorRow ]
@@ -140,6 +179,11 @@ func (v *SkillsView) installSelected() {
140179}
141180
142181func (v * SkillsView ) installAllForSelectedSkill () {
182+ if len (AvailableSkills ) == 0 {
183+ v .message = "No skills available"
184+ return
185+ }
186+
143187 installed := 0
144188 skill := AvailableSkills [v .cursorRow ]
145189
@@ -158,6 +202,11 @@ func (v *SkillsView) installAllForSelectedSkill() {
158202}
159203
160204func (v * SkillsView ) removeSelected () {
205+ if len (AvailableSkills ) == 0 {
206+ v .message = "No skills available"
207+ return
208+ }
209+
161210 status := & v .agents [v .cursorCol ]
162211 agentName := status .Agent .Name ()
163212 skill := AvailableSkills [v .cursorRow ]
@@ -225,8 +274,14 @@ func (v *SkillsView) View() string {
225274 b .WriteString (borderStyle .Render (" " + strings .Repeat ("─" , 70 )))
226275 b .WriteString ("\n " )
227276
277+ // Check if skills are available
278+ if len (AvailableSkills ) == 0 {
279+ b .WriteString ("\n No skills available. Press 'R' to refresh from registry.\n " )
280+ return b .String ()
281+ }
282+
228283 // Column headers (Agent names)
229- b .WriteString (" " )
284+ b .WriteString (" " )
230285 for i , status := range v .agents {
231286 style := colHeaderStyle
232287 if i == v .cursorCol {
@@ -251,12 +306,12 @@ func (v *SkillsView) View() string {
251306 row .WriteString (" " )
252307 }
253308
254- // Skill name
309+ // Skill name - width 28 characters for long names
255310 name := skill .Name
256- if len (name ) > 14 {
257- name = name [:14 ]
311+ if len (name ) > 28 {
312+ name = name [:28 ]
258313 }
259- row .WriteString (fmt .Sprintf ("%-14s " , name ))
314+ row .WriteString (fmt .Sprintf ("%-28s " , name ))
260315
261316 // Status for each agent
262317 for agentIdx , status := range v .agents {
@@ -316,6 +371,7 @@ func (v *SkillsView) ShortHelp() []components.FooterAction {
316371 {Key : "←→" , Label : "select agent" },
317372 {Key : "↑↓" , Label : "select skill" },
318373 {Key : "c" , Label : "check" },
374+ {Key : "R" , Label : "refresh" },
319375 {Key : "q" , Label : "quit" },
320376 }
321377}
0 commit comments