返回 DeepSeek-Reasonix
skill.go
根目录 / internal / control / skill.go
1 package control
2
3 import "reasonix/internal/skill"
4
5 // skillSet owns the session's discovered skills: the enabled subset surfaced to
6 // the model, the full set (including config-disabled ones) for management
7 // surfaces, and the optional reloadable stores that supersede the
8 // construction-time snapshots. It is the skills slice of the Capabilities concern
9 // (alongside mcpManager).
10 //
11 // No lock: every field is set once at construction and only read thereafter.
12 // Skills are discovered at boot and never mutated in place — SetSkillEnabled
13 // persists a config preference and relies on a controller rebuild to take effect.
14 type skillSet struct {
15 enabled []skill.Skill // discovered + enabled skills (the live store supersedes when set)
16 all []skill.Skill // every discoverable skill, including config-disabled ones
17 store *skill.Store // reloadable enabled-skill store; nil falls back to enabled
18 allStore *skill.Store // reloadable all-skill store; nil falls back to all/enabled
19 }
20
21 func newSkillSet(enabled, all []skill.Skill, store, allStore *skill.Store) skillSet {
22 return skillSet{enabled: enabled, all: all, store: store, allStore: allStore}
23 }
24
25 // list returns the enabled skills, preferring the live store.
26 func (s *skillSet) list() []skill.Skill {
27 if s.store != nil {
28 return s.store.List()
29 }
30 return s.enabled
31 }
32
33 func (s *skillSet) slashList() []skill.Skill {
34 if s.store != nil {
35 return s.store.SlashList()
36 }
37 return skill.VisibleSlashSkills(s.enabled)
38 }
39
40 // listAll returns every discoverable skill (including disabled), preferring the
41 // live store, for management surfaces that re-enable a hidden skill.
42 func (s *skillSet) listAll() []skill.Skill {
43 if s.allStore != nil {
44 return s.allStore.List()
45 }
46 if len(s.all) > 0 {
47 return s.all
48 }
49 return s.enabled
50 }
51
52 func (s *skillSet) load(name string) (skill.Skill, bool) {
53 if s.allStore != nil {
54 return s.allStore.Read(name)
55 }
56 if s.store != nil {
57 return s.store.Read(name)
58 }
59 for _, candidate := range s.listAll() {
60 if candidate.Name == name {
61 return candidate, true
62 }
63 }
64 return skill.Skill{}, false
65 }
66
67 func (s *skillSet) bySlashName(name string) (skill.Skill, bool) {
68 if s.store != nil {
69 return s.store.ReadSlash(name)
70 }
71 return skill.ResolveSlashSkill(s.enabled, name)
72 }
73
74 func (s *skillSet) prepare(sk skill.Skill) skill.Skill {
75 if s.store != nil {
76 return s.store.Prepare(sk)
77 }
78 return sk
79 }
80
81 func (s *skillSet) render(sk skill.Skill, args string) string {
82 if s.store != nil {
83 return s.store.Render(sk, args)
84 }
85 return skill.Render(sk, args)
86 }
87
88 // writer returns the live store to use for authoring (create/delete), preferring
89 // allStore since management surfaces must resolve disabled and builtin skills
90 // too (e.g. a create-time name-collision check). nil when this session has no
91 // reloadable store (e.g. a construction-time-only test snapshot).
92 func (s *skillSet) writer() *skill.Store {
93 if s.allStore != nil {
94 return s.allStore
95 }
96 return s.store
97 }
98
98 lines GO