返回 DeepSeek-Reasonix
mcp_import_picker.go
根目录 / internal / cli / mcp_import_picker.go
1 package cli
2
3 import (
4 "fmt"
5 "strings"
6
7 tea "charm.land/bubbletea/v2"
8
9 "reasonix/internal/config"
10 )
11
12 type mcpImportPicker struct {
13 candidates []config.MCPImportCandidate
14 cursor int
15 checked []bool
16 }
17
18 func newMCPImportPicker(candidates []config.MCPImportCandidate) *mcpImportPicker {
19 p := &mcpImportPicker{candidates: candidates, checked: make([]bool, len(candidates))}
20 for i, c := range candidates {
21 p.checked[i] = c.Recommended
22 }
23 return p
24 }
25
26 func (m *chatTUI) openMCPImportPicker() {
27 candidates, err := config.LoadCCSwitchMCPCandidates()
28 if err != nil {
29 m.notice("mcp import: " + err.Error())
30 return
31 }
32 if len(candidates) == 0 {
33 m.notice("mcp import: no candidates found")
34 return
35 }
36 m.completion = completion{}
37 m.mcpImport = newMCPImportPicker(candidates)
38 }
39
40 func (m chatTUI) handleMCPImportKey(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
41 p := m.mcpImport
42 switch msg.String() {
43 case "esc", "ctrl+c":
44 m.mcpImport = nil
45 return m, nil
46 case "up", "k":
47 if p.cursor > 0 {
48 p.cursor--
49 }
50 case "down", "j":
51 if p.cursor < len(p.candidates)-1 {
52 p.cursor++
53 }
54 case " ", "space":
55 p.checked[p.cursor] = !p.checked[p.cursor]
56 case "enter":
57 var entries []config.PluginEntry
58 for i, ok := range p.checked {
59 if ok {
60 entries = append(entries, p.candidates[i].Entry)
61 }
62 }
63 m.mcpImport = nil
64 if len(entries) == 0 {
65 m.notice("mcp import: nothing selected")
66 return m, nil
67 }
68 total, added, updated, connected, failed, skipped, err := m.ctrl.ImportMCPEntries(entries)
69 if err != nil {
70 m.notice("mcp import: " + err.Error())
71 return m, nil
72 }
73 m.refreshHostAndInvalidateSlashCatalog()
74 m.notice(fmt.Sprintf("imported %d selected MCP servers from cc-switch (%d added, %d updated, %d connected, %d failed, %d skipped)", total, added, updated, connected, failed, skipped))
75 }
76 return m, nil
77 }
78
79 func (m chatTUI) renderMCPImport() string {
80 p := m.mcpImport
81 if p == nil {
82 return ""
83 }
84 w := max(m.width, 10)
85 var b strings.Builder
86 b.WriteString(accent("Import MCP from cc-switch") + "\n")
87 b.WriteString(dim("Space select · Enter import · Esc cancel") + "\n\n")
88 for i, c := range p.candidates {
89 box := "[ ]"
90 if p.checked[i] {
91 box = "[x]"
92 }
93 mark := " "
94 if i == p.cursor {
95 mark = "›"
96 }
97 reasons := strings.Join(c.Reasons, ", ")
98 line := fmt.Sprintf("%s %s %-34s %s", mark, box, c.Entry.Name, dim(reasons))
99 if i == p.cursor {
100 line = reverse(line)
101 }
102 b.WriteString(line + "\n")
103 }
104 return choicePanelStyle.Width(w).Render(strings.TrimRight(b.String(), "\n"))
105 }
106
106 lines GO