Skip to content

Commit 6871a79

Browse files
committed
chore(lint): upgrade golangci-lint config to v2 and fix staticcheck findings
- Migrate .golangci.yml to the v2 schema. - Fix staticcheck quick-fix findings (QF1012, QF1003, QF1004, QF1002, ST1005) across cmd/odek and internal/skills. - Move verbose installation hints for whisper/vision tools from error strings to stderr so returned errors stay single-line and punctuation-free.
1 parent 55068ed commit 6871a79

16 files changed

Lines changed: 172 additions & 221 deletions

.golangci.yml

Lines changed: 114 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -1,178 +1,123 @@
1-
# golangci-lint configuration for odek.
2-
#
3-
# Goal: enable a core set of linters in CI without requiring a one-shot
4-
# refactor of the whole codebase. Test files are excluded from the noisiest
5-
# rules (errcheck, unused) because setup helpers frequently ignore errors or
6-
# are conditionally compiled. Pre-existing production issues are listed below
7-
# with explicit excludes so CI stays green; they should be removed as the code
8-
# is touched.
1+
version: "2"
92
run:
10-
timeout: 10m
113
go: "1.25"
12-
134
linters:
5+
default: none
146
enable:
157
- errcheck
16-
- gosimple
178
- govet
189
- ineffassign
1910
- staticcheck
2011
- unused
21-
22-
linters-settings:
23-
errcheck:
24-
# Ignore common error-delegation patterns where the error is handled
25-
# implicitly (e.g. fmt.Fprintf to stderr).
26-
exclude-functions:
27-
- fmt.Fprintf
28-
- fmt.Fprintln
29-
- io.WriteString
30-
31-
issues:
32-
exclude-rules:
33-
# Test helpers commonly ignore setup errors, may define conditionally unused
34-
# helpers, and often contain intentionally empty branches / identical
35-
# comparison assertions. Keep govet enabled for tests; silence the rest.
36-
- path: _test\.go
37-
linters:
38-
- errcheck
39-
- gosimple
40-
- ineffassign
41-
- staticcheck
42-
- unused
43-
44-
# ------------------------------------------------------------------
45-
# Pre-existing production issues to be fixed incrementally. Each entry
46-
# points to a concrete lint finding that existed before golangci-lint
47-
# was enabled in CI. Contributors should remove the matching exclude
48-
# when fixing the underlying code.
49-
# ------------------------------------------------------------------
50-
51-
# cmd/odek/file_tool.go: unchecked filepath.Walk errors.
52-
- path: cmd/odek/file_tool.go
53-
linters:
54-
- errcheck
55-
56-
# cmd/odek/main.go: unchecked fmt.Sscanf/Scanf/store.Save/sl.RecordSkip.
57-
- path: cmd/odek/main.go
58-
linters:
59-
- errcheck
60-
61-
# cmd/odek/mcp.go: unchecked error return.
62-
- path: cmd/odek/mcp.go
63-
linters:
64-
- errcheck
65-
66-
# cmd/odek/perf_tools.go: unchecked Walk/Seek/io.Copy/Process.Kill.
67-
- path: cmd/odek/perf_tools.go
68-
linters:
69-
- errcheck
70-
71-
# cmd/odek/repl.go: unchecked store.Save.
72-
- path: cmd/odek/repl.go
73-
linters:
74-
- errcheck
75-
76-
# cmd/odek/repl_editor.go: unchecked terminal restore/read.
77-
- path: cmd/odek/repl_editor.go
78-
linters:
79-
- errcheck
80-
81-
# cmd/odek/serve.go: unchecked error returns + unused wsStreamWriter.
82-
- path: cmd/odek/serve.go
83-
linters:
84-
- errcheck
85-
- unused
86-
87-
# cmd/odek/telegram.go: unchecked bot.* and os.MkdirAll error returns.
88-
- path: cmd/odek/telegram.go
89-
linters:
90-
- errcheck
91-
92-
# cmd/odek/wsapprover.go: unchecked rand.Read error.
93-
- path: cmd/odek/wsapprover.go
94-
linters:
95-
- errcheck
96-
97-
# cmd/odek/subagent.go: unchecked enc.Encode.
98-
- path: cmd/odek/subagent.go
99-
linters:
100-
- errcheck
101-
102-
# cmd/odek/vision_tool.go: unchecked fmt.Sscanf.
103-
- path: cmd/odek/vision_tool.go
104-
linters:
105-
- errcheck
106-
107-
# internal/memory/memory.go: unchecked episode write.
108-
- path: internal/memory/memory.go
109-
linters:
110-
- errcheck
111-
112-
# internal/skills/cache.go/tools.go/types.go: unchecked Rename/Unmarshal.
113-
- path: internal/skills/cache.go
114-
linters:
115-
- errcheck
116-
- path: internal/skills/tools.go
117-
linters:
118-
- errcheck
119-
- path: internal/skills/types.go
120-
linters:
121-
- errcheck
122-
123-
# internal/flock/flock.go: unchecked unlockFile.
124-
- path: internal/flock/flock.go
125-
linters:
126-
- errcheck
127-
128-
# internal/telegram/approver.go: unchecked EditMessageText/rand.Read.
129-
- path: internal/telegram/approver.go
130-
linters:
131-
- errcheck
132-
133-
# internal/telegram/health.go: unchecked json.Encode.
134-
- path: internal/telegram/health.go
135-
linters:
136-
- errcheck
137-
138-
# internal/llm/client.go: unused var + empty branch.
139-
- path: internal/llm/client.go
140-
linters:
141-
- unused
142-
- staticcheck
143-
144-
# internal/loop/loop.go: unnecessary fmt.Sprintf.
145-
- path: internal/loop/loop.go
146-
linters:
147-
- gosimple
148-
149-
# internal/mcpclient/client.go: unused type/fields/function + unchecked Wait/Kill.
150-
- path: internal/mcpclient/client.go
151-
linters:
152-
- errcheck
153-
- unused
154-
155-
# internal/memory/buffer.go: unnecessary fmt.Sprintf.
156-
- path: internal/memory/buffer.go
157-
linters:
158-
- gosimple
159-
160-
# internal/memory/memory.go: unused const.
161-
- path: internal/memory/memory.go
162-
linters:
163-
- unused
164-
165-
# internal/memory/merge.go: ineffectual assignments.
166-
- path: internal/memory/merge.go
167-
linters:
168-
- ineffassign
169-
170-
# internal/telegram/bot.go: deprecated netErr.Temporary.
171-
- path: internal/telegram/bot.go
172-
linters:
173-
- staticcheck
174-
175-
# internal/schedule/store.go: unchecked syscall.Flock.
176-
- path: internal/schedule/store.go
177-
linters:
178-
- errcheck
12+
settings:
13+
errcheck:
14+
exclude-functions:
15+
- fmt.Fprintf
16+
- fmt.Fprintln
17+
- io.WriteString
18+
exclusions:
19+
generated: lax
20+
presets:
21+
- comments
22+
- common-false-positives
23+
- legacy
24+
- std-error-handling
25+
rules:
26+
- linters:
27+
- errcheck
28+
- ineffassign
29+
- staticcheck
30+
- unused
31+
path: _test\.go
32+
- linters:
33+
- errcheck
34+
path: cmd/odek/file_tool.go
35+
- linters:
36+
- errcheck
37+
path: cmd/odek/main.go
38+
- linters:
39+
- errcheck
40+
path: cmd/odek/mcp.go
41+
- linters:
42+
- errcheck
43+
path: cmd/odek/perf_tools.go
44+
- linters:
45+
- errcheck
46+
path: cmd/odek/repl.go
47+
- linters:
48+
- errcheck
49+
path: cmd/odek/repl_editor.go
50+
- linters:
51+
- errcheck
52+
- unused
53+
path: cmd/odek/serve.go
54+
- linters:
55+
- errcheck
56+
path: cmd/odek/telegram.go
57+
- linters:
58+
- errcheck
59+
path: cmd/odek/wsapprover.go
60+
- linters:
61+
- errcheck
62+
path: cmd/odek/subagent.go
63+
- linters:
64+
- errcheck
65+
path: cmd/odek/vision_tool.go
66+
- linters:
67+
- errcheck
68+
path: internal/memory/memory.go
69+
- linters:
70+
- errcheck
71+
path: internal/skills/cache.go
72+
- linters:
73+
- errcheck
74+
path: internal/skills/tools.go
75+
- linters:
76+
- errcheck
77+
path: internal/skills/types.go
78+
- linters:
79+
- errcheck
80+
path: internal/flock/flock.go
81+
- linters:
82+
- errcheck
83+
path: internal/telegram/approver.go
84+
- linters:
85+
- errcheck
86+
path: internal/telegram/health.go
87+
- linters:
88+
- staticcheck
89+
- unused
90+
path: internal/llm/client.go
91+
- linters:
92+
- staticcheck
93+
path: internal/loop/loop.go
94+
- linters:
95+
- errcheck
96+
- unused
97+
path: internal/mcpclient/client.go
98+
- linters:
99+
- staticcheck
100+
path: internal/memory/buffer.go
101+
- linters:
102+
- unused
103+
path: internal/memory/memory.go
104+
- linters:
105+
- ineffassign
106+
path: internal/memory/merge.go
107+
- linters:
108+
- staticcheck
109+
path: internal/telegram/bot.go
110+
- linters:
111+
- errcheck
112+
path: internal/schedule/store.go
113+
paths:
114+
- third_party$
115+
- builtin$
116+
- examples$
117+
formatters:
118+
exclusions:
119+
generated: lax
120+
paths:
121+
- third_party$
122+
- builtin$
123+
- examples$

cmd/odek/file_tool.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func confinedGlob(root, pattern string, limit int, includeDirs bool) ([]string,
5555
// does not match "..", but a pattern like "../.ssh/id_*" combined with
5656
// filepath.Glob would traverse upward. We block it explicitly.
5757
if strings.Contains(pattern, "..") {
58-
return nil, fmt.Errorf("pattern cannot contain ..")
58+
return nil, fmt.Errorf("pattern cannot contain parent directory references")
5959
}
6060
if filepath.IsAbs(pattern) {
6161
return nil, fmt.Errorf("pattern cannot be absolute")

cmd/odek/main.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2119,9 +2119,10 @@ func skillCmd(args []string) error {
21192119
fmt.Fprintf(os.Stderr, "━━━━━━━━━━━━━━━\n")
21202120
if assessment != nil {
21212121
riskSymbol := "🟢"
2122-
if assessment.RiskClass == "elevated" {
2122+
switch assessment.RiskClass {
2123+
case "elevated":
21232124
riskSymbol = "🟡"
2124-
} else if assessment.RiskClass == "dangerous" {
2125+
case "dangerous":
21252126
riskSymbol = "🔴"
21262127
}
21272128
fmt.Fprintf(os.Stderr, "Risk: %s %s\n", riskSymbol, assessment.RiskClass)

cmd/odek/perf_tools.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2414,7 +2414,7 @@ func (t *trTool) Call(argsJSON string) (result string, err error) {
24142414
return r
24152415
}, text)
24162416
} else {
2417-
text = strings.Replace(text, tf.From, tf.To, -1)
2417+
text = strings.ReplaceAll(text, tf.From, tf.To)
24182418
}
24192419
case "string":
24202420
if tf.From == "" {

cmd/odek/repl_editor.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ func (e *replEditor) handleEscape() (bool, error) {
136136
return false, err
137137
}
138138

139-
switch {
140-
case buf[0] == '[':
139+
switch buf[0] {
140+
case '[':
141141
// CSI sequence
142142
n, err = os.Stdin.Read(buf[:1])
143143
if err != nil || n < 1 {
@@ -164,7 +164,7 @@ func (e *replEditor) handleEscape() (bool, error) {
164164
case '1': // Bracketed paste end \x1b[201~
165165
e.readTildeOrBracketed("")
166166
}
167-
case buf[0] == 'O': // Old-style home/end
167+
case 'O': // Old-style home/end
168168
n, err = os.Stdin.Read(buf[:1])
169169
if err != nil || n < 1 {
170170
return false, err

cmd/odek/serve.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1260,7 +1260,7 @@ func checkLocalOrigin(_ *golangws.Config, req *http.Request) error {
12601260
if host == "localhost" || host == "127.0.0.1" || host == "::1" {
12611261
return nil
12621262
}
1263-
return fmt.Errorf("Origin %q not allowed (only localhost is accepted)", origin)
1263+
return fmt.Errorf("origin %q not allowed (only localhost is accepted)", origin)
12641264
}
12651265

12661266
const (

cmd/odek/subagent_tool.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ func (t *delegateTasksTool) Call(args string) (string, error) {
162162
var buf strings.Builder
163163
buf.WriteString("📋 Sub-agent results:\n\n")
164164
for i, r := range results {
165-
buf.WriteString(fmt.Sprintf("─── Task %d: %s ───\n", i+1, truncate(input.Tasks[i].Goal, 60)))
165+
fmt.Fprintf(&buf, "─── Task %d: %s ───\n", i+1, truncate(input.Tasks[i].Goal, 60))
166166
if len(r) > maxSubagentSummaryResultBytes {
167167
buf.WriteString(r[:maxSubagentSummaryResultBytes])
168168
buf.WriteString("\n... [result truncated]")

cmd/odek/telegram.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1712,13 +1712,14 @@ func handleChatMessage(
17121712
return
17131713
}
17141714

1715-
if toolProgress == "verbose" {
1715+
switch toolProgress {
1716+
case "verbose":
17161717
recordToolStart()
17171718
line := fmt.Sprintf("%s `%s` %s", render.ToolEmoji(name), name, truncateToolArgs(data, 2000))
17181719
line = telegram.EscapeMarkdown(line)
17191720
bot.SendMessage(chatID, line,
17201721
&telegram.SendOpts{ParseMode: telegram.ParseModeMarkdownV2})
1721-
} else if toolProgress == "all" || toolProgress == "new" {
1722+
case "all", "new":
17221723
// Insert reasoning header (first sentence) at top of bubble
17231724
if reasoningProgressLine != "" {
17241725
if len(progressLines) == 0 || progressLines[0] != reasoningProgressLine {

0 commit comments

Comments
 (0)