返回 DeepSeek-Reasonix
skill_view.go
根目录 / internal / cli / skill_view.go
1 package cli
2
3 import (
4 "fmt"
5 "strings"
6
7 "reasonix/internal/skill"
8 )
9
10 const skillShowMaxLines = 80
11
12 func renderSkillList(width int, skills []skill.Skill, disabled map[string]bool) string {
13 var b strings.Builder
14 fmt.Fprintf(&b, "%s\n", viewHeader("skills (%d)", len(skills)))
15 for _, s := range skills {
16 name := "/" + s.SlashName()
17 scope := "(" + string(s.Scope) + ")"
18 tag := ""
19 if s.RunAs == skill.RunSubagent {
20 tag = " " + viewStatus("subagent")
21 }
22 if disabled[s.Name] {
23 tag += " " + viewMeta("disabled")
24 }
25 used := 2 + viewPadWidth(name, 18) + 1 + visibleWidth(scope) + 2 + visibleWidth(tag)
26 desc := viewCompactText(s.Description, viewBudget(width, used))
27 fmt.Fprintf(&b, " %-18s %s %s%s\n", name, viewMeta(scope), desc, tag)
28 }
29 b.WriteString(viewHint(viewCompactText("invoke: /<name> [args] · manage: /skills manage · author: /skills new <name>", viewBudget(width, 2))))
30 return strings.TrimRight(b.String(), "\n")
31 }
32
33 func renderSkillShow(width int, s skill.Skill, disabled bool) string {
34 var b strings.Builder
35 fmt.Fprintf(&b, "%s %s\n", viewHeader("skill:"), viewCompactText(s.SlashName(), viewBudget(width, 7)))
36 if s.RunAs == skill.RunSubagent {
37 fmt.Fprintf(&b, " %s %s\n", viewMeta(string(s.Scope)), viewStatus("subagent"))
38 } else {
39 fmt.Fprintf(&b, " %s\n", viewMeta(string(s.Scope)))
40 }
41 if s.Plugin != "" {
42 fmt.Fprintf(&b, " %s\n", viewMeta("plugin "+s.Plugin))
43 }
44 if disabled {
45 fmt.Fprintf(&b, " %s\n", viewMeta("disabled"))
46 }
47 if strings.TrimSpace(s.Description) != "" {
48 fmt.Fprintf(&b, " %s\n", viewCompactText(s.Description, viewBudget(width, 2)))
49 }
50 if strings.TrimSpace(s.Path) != "" {
51 fmt.Fprintf(&b, " %s\n", viewMeta(viewCompactPath(s.Path, viewBudget(width, 2))))
52 }
53 body, extra := viewBodyPreview(s.Body, skillShowMaxLines)
54 if strings.TrimSpace(body) != "" {
55 b.WriteString("\n")
56 b.WriteString(viewProtectLines(body, width))
57 }
58 if extra > 0 {
59 if b.Len() > 0 {
60 b.WriteByte('\n')
61 }
62 b.WriteString(viewMore(extra, "lines"))
63 }
64 return strings.TrimRight(b.String(), "\n")
65 }
66
67 func renderSkillPaths(width int, roots []skill.Root) string {
68 var b strings.Builder
69 fmt.Fprintf(&b, "%s\n", viewHeader("skill paths"))
70 for _, r := range roots {
71 leftWidth := 2 + 4 + 8 + 1 + 13 + 1
72 scope := viewMeta(fmt.Sprintf("%-8s", string(r.Scope)))
73 status := fmt.Sprintf("%-13s", string(r.Status))
74 if r.Status == skill.StatusOK {
75 status = viewStatus(status)
76 } else {
77 status = viewMeta(status)
78 }
79 fmt.Fprintf(&b, " %2d. %s %s %s\n",
80 r.Priority+1, scope, status, viewCompactPath(r.Dir, viewBudget(width, leftWidth)))
81 }
82 b.WriteString(viewHint(viewCompactText("priority: project > custom > global > builtin · configure [skills] paths in reasonix.toml", viewBudget(width, 2))))
83 return strings.TrimRight(b.String(), "\n")
84 }
85
85 lines GO