on main help sign in
refactor: modernize (#2548)
e3df84eBruno Krugel
internal/agent/loop_detection_test.go+3−3
@@ -80,7 +80,7 @@ func TestHasRepeatedToolCalls(t *testing.T) {
80 t.Run("exact repeat at threshold not detected", func(t *testing.T) {
80 t.Run("exact repeat at threshold not detected", func(t *testing.T) {
81 // maxRepeats=5 means > 5 is needed, so exactly 5 should return false
81 // maxRepeats=5 means > 5 is needed, so exactly 5 should return false
82 steps := make([]fantasy.StepResult, 10)
82 steps := make([]fantasy.StepResult, 10)
83− for i := 0; i < 5; i++ {
83+ for i := range 5 {
84 steps[i] = makeToolStep("read", `{"file":"a.go"}`, "content")
84 steps[i] = makeToolStep("read", `{"file":"a.go"}`, "content")
85 }
85 }
86 for i := 5; i < 10; i++ {
86 for i := 5; i < 10; i++ {
@@ -95,7 +95,7 @@ func TestHasRepeatedToolCalls(t *testing.T) {
95 t.Run("loop detected", func(t *testing.T) {
95 t.Run("loop detected", func(t *testing.T) {
96 // 6 identical steps in a window of 10 with maxRepeats=5 → detected
96 // 6 identical steps in a window of 10 with maxRepeats=5 → detected
97 steps := make([]fantasy.StepResult, 10)
97 steps := make([]fantasy.StepResult, 10)
98− for i := 0; i < 6; i++ {
98+ for i := range 6 {
99 steps[i] = makeToolStep("read", `{"file":"a.go"}`, "content")
99 steps[i] = makeToolStep("read", `{"file":"a.go"}`, "content")
100 }
100 }
101 for i := 6; i < 10; i++ {
101 for i := 6; i < 10; i++ {
@@ -110,7 +110,7 @@ func TestHasRepeatedToolCalls(t *testing.T) {
110 t.Run("steps without tool calls are skipped", func(t *testing.T) {
110 t.Run("steps without tool calls are skipped", func(t *testing.T) {
111 // Mix of tool steps and empty steps — empty ones should not affect counts
111 // Mix of tool steps and empty steps — empty ones should not affect counts
112 steps := make([]fantasy.StepResult, 10)
112 steps := make([]fantasy.StepResult, 10)
113− for i := 0; i < 4; i++ {
113+ for i := range 4 {
114 steps[i] = makeToolStep("read", `{"file":"a.go"}`, "content")
114 steps[i] = makeToolStep("read", `{"file":"a.go"}`, "content")
115 }
115 }
116 for i := 4; i < 8; i++ {
116 for i := 4; i < 8; i++ {
internal/cmd/session.go+1−4
@@ -171,10 +171,7 @@ func runSessionList(cmd *cobra.Command, _ []string) error {
171 width = tw
171 width = tw
172 }
172 }
173 // 7 (hash) + 1 (space) + 25 (RFC3339 date) + 1 (space) = 34 chars prefix.
173 // 7 (hash) + 1 (space) + 25 (RFC3339 date) + 1 (space) = 34 chars prefix.
174− titleWidth := width - 34
174+ titleWidth := max(width-34, 10)
175− if titleWidth < 10 {
176− titleWidth = 10
177− }
178
175
179 var writeErr error
176 var writeErr error
180 for _, s := range list {
177 for _, s := range list {
internal/shell/background.go+3−3
@@ -56,7 +56,7 @@ type BackgroundShell struct {
56 stderr *syncBuffer
56 stderr *syncBuffer
57 done chan struct{}
57 done chan struct{}
58 exitErr error
58 exitErr error
59− completedAt int64 // Unix timestamp when job completed (0 if still running)
59+ completedAt atomic.Int64 // Unix timestamp when job completed (0 if still running)
60}
60}
61
61
62// BackgroundShellManager manages background shell instances.
62// BackgroundShellManager manages background shell instances.
@@ -122,7 +122,7 @@ func (m *BackgroundShellManager) Start(ctx context.Context, workingDir string, b
122 err := shell.ExecStream(shellCtx, command, bgShell.stdout, bgShell.stderr)
122 err := shell.ExecStream(shellCtx, command, bgShell.stdout, bgShell.stderr)
123
123
124 bgShell.exitErr = err
124 bgShell.exitErr = err
125− atomic.StoreInt64(&bgShell.completedAt, time.Now().Unix())
125+ bgShell.completedAt.Store(time.Now().Unix())
126 }()
126 }()
127
127
128 return bgShell, nil
128 return bgShell, nil
@@ -178,7 +178,7 @@ func (m *BackgroundShellManager) Cleanup() int {
178
178
179 var toRemove []string
179 var toRemove []string
180 for shell := range m.shells.Seq() {
180 for shell := range m.shells.Seq() {
181− completedAt := atomic.LoadInt64(&shell.completedAt)
181+ completedAt := shell.completedAt.Load()
182 if completedAt > 0 && now-completedAt > retentionSeconds {
182 if completedAt > 0 && now-completedAt > retentionSeconds {
183 toRemove = append(toRemove, shell.ID)
183 toRemove = append(toRemove, shell.ID)
184 }
184 }
internal/ui/anim/anim.go+2−2
@@ -57,10 +57,10 @@ var (
57
57
58// Internal ID management. Used during animating to ensure that frame messages
58// Internal ID management. Used during animating to ensure that frame messages
59// are received only by spinner components that sent them.
59// are received only by spinner components that sent them.
60−var lastID int64
60+var lastID atomic.Int64
61
61
62func nextID() int {
62func nextID() int {
63− return int(atomic.AddInt64(&lastID, 1))
63+ return int(lastID.Add(1))
64}
64}
65
65
66// Cache for expensive animation calculations
66// Cache for expensive animation calculations
internal/ui/completions/completions.go+2−7
@@ -257,14 +257,9 @@ func namePriorityTier(path, queryLower string) int {
257}
257}
258
258
259func hasPathSegment(pathLower, queryLower string) bool {
259func hasPathSegment(pathLower, queryLower string) bool {
260− for _, part := range strings.FieldsFunc(pathLower, func(r rune) bool {
260+ return slices.Contains(strings.FieldsFunc(pathLower, func(r rune) bool {
261 return r == '/' || r == '\\'
261 return r == '/' || r == '\\'
262− }) {
263− if part == queryLower {
262+ }), queryLower)
264− return true
265− }
266− }
267− return false
268}
263}
269
264
270func (c *Completions) updateSize() {
265func (c *Completions) updateSize() {