1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
package tmuxedit
import (
"testing"
"codeberg.org/snonux/hexai/internal/appconfig"
)
func boolP(b bool) *bool { return &b }
func TestResolveAgents_MergeOverride(t *testing.T) {
// Override the built-in "amp" agent to verify config merging preserves
// builtin fields (detectPattern) while applying user overrides (DisplayName, ClearFirst).
cfgAgents := []appconfig.TmuxEditAgentCfg{
{
Name: "amp",
DisplayName: "My Amp",
ClearFirst: boolP(false),
},
}
agents := resolveAgents(cfgAgents)
var amp Agent
for _, a := range agents {
if a.Name() == "amp" {
amp = a
break
}
}
if amp == nil {
t.Fatal("amp agent not found")
}
if amp.DisplayName() != "My Amp" {
t.Errorf("DisplayName = %q, want My Amp", amp.DisplayName())
}
// ClearInput should be no-op after override to false
c := amp.(Configurable)
if c.Base().clearFirst {
t.Error("clearFirst should be false after override")
}
// DetectPattern should be preserved from builtin
if c.Base().detectPattern == "" {
t.Error("detectPattern should be preserved from builtin")
}
}
func TestResolveAgents_MergeAllFields(t *testing.T) {
// Override the built-in "aider" agent with all fields to verify full merging.
cfgAgents := []appconfig.TmuxEditAgentCfg{
{
Name: "aider",
DisplayName: "Custom Aider",
DetectPattern: "(?i)custom-aider",
PromptPattern: `>\s+(.*)$`,
StripPatterns: []string{"NOISE"},
ClearFirst: boolP(true),
ClearKeys: "C-k",
NewlineKeys: "C-Enter",
SubmitKeys: "C-m",
},
}
agents := resolveAgents(cfgAgents)
var a Agent
for _, ag := range agents {
if ag.Name() == "aider" {
a = ag
break
}
}
if a == nil {
t.Fatal("aider agent not found")
}
c := a.(Configurable)
base := c.Base()
if base.detectPattern != "(?i)custom-aider" {
t.Errorf("detectPattern = %q", base.detectPattern)
}
if base.promptPat != `>\s+(.*)$` {
t.Errorf("promptPat = %q", base.promptPat)
}
if len(base.stripPatterns) != 1 || base.stripPatterns[0] != "NOISE" {
t.Errorf("stripPatterns = %v", base.stripPatterns)
}
if base.clearKeys != "C-k" {
t.Errorf("clearKeys = %q", base.clearKeys)
}
if base.newlineKeys != "C-Enter" {
t.Errorf("newlineKeys = %q", base.newlineKeys)
}
if base.submitKeys != "C-m" {
t.Errorf("submitKeys = %q", base.submitKeys)
}
}
func TestResolveAgents_AddNew(t *testing.T) {
cfgAgents := []appconfig.TmuxEditAgentCfg{
{
Name: "custom",
DisplayName: "Custom Agent",
DetectPattern: "(?i)custom",
PromptPattern: `>\s*(.+)$`,
ClearFirst: boolP(true),
},
}
agents := resolveAgents(cfgAgents)
found := false
for _, a := range agents {
if a.Name() == "custom" {
found = true
if a.DisplayName() != "Custom Agent" {
t.Errorf("DisplayName = %q, want Custom Agent", a.DisplayName())
}
c := a.(Configurable)
if !c.Base().clearFirst {
t.Error("clearFirst should be true")
}
}
}
if !found {
t.Error("custom agent not found in resolved agents")
}
}
func TestAgentFromConfig_DefaultDisplayName(t *testing.T) {
cfg := appconfig.TmuxEditAgentCfg{
Name: "test",
}
a := agentFromConfig(cfg)
if a.DisplayName() != "test" {
t.Errorf("DisplayName = %q, want test (defaulted from Name)", a.DisplayName())
}
}
func TestConfigAgent_ExtractPrompt(t *testing.T) {
// Config agent uses baseAgent's default extraction (section-aware)
agent := &configAgent{baseAgent{
promptPat: `(?m)>\s*(.+)$`,
}}
content := "> hello world"
got := agent.ExtractPrompt(content)
if got != "hello world" {
t.Errorf("ExtractPrompt() = %q, want %q", got, "hello world")
}
}
func TestConfigAgent_Amp(t *testing.T) {
agents := builtinAgents()
var amp Agent
for _, a := range agents {
if a.Name() == "amp" {
amp = a
break
}
}
if amp == nil {
t.Fatal("amp agent not found")
}
if !amp.Detect("Amp by Sourcegraph") {
t.Error("amp should detect 'Amp by Sourcegraph'")
}
// Amp uses box-drawing TUI format (like cursor), not shell-style > prompt
got := amp.ExtractPrompt("│ fix the bug │")
if got != "fix the bug" {
t.Errorf("ExtractPrompt() = %q, want %q", got, "fix the bug")
}
}
func TestConfigAgent_Aider(t *testing.T) {
agents := builtinAgents()
var aider Agent
for _, a := range agents {
if a.Name() == "aider" {
aider = a
break
}
}
if aider == nil {
t.Fatal("aider agent not found")
}
if !aider.Detect("aider v0.50") {
t.Error("aider should detect 'aider v0.50'")
}
}
|