536d31d9c47926c63a255e5e6c6e424844e8501f

Author
TheEdgeOfRage <git@theedgeofrage.com>
Committer
TheEdgeOfRage <git@theedgeofrage.com>
Date

Message

lint: fix errcheck and staticcheck findings

Diff

  1diff --git a/cmd/jp/main.go b/cmd/jp/main.go
  2index f2b292ea93ac9b4dd5fd2eb40c86f07893253223..f4280f829ac62bc6c814b5c3742b343ee2ff3b58 100644
  3--- a/cmd/jp/main.go
  4+++ b/cmd/jp/main.go
  5@@ -167,10 +167,10 @@ func genPersonaCmd(args []string) {
  6 
  7 	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
  8 	defer cancel()
  9-	client := llm.NewClient(opts.Config.LLMBaseURL, nil)
 10+	client := llm.NewClient(opts.LLMBaseURL, nil)
 11 	draft, err := persona.GenerateDraft(ctx, client, opts.Role)
 12 	if err != nil {
 13-		fmt.Fprintf(os.Stderr, "persona gen: LLM service at %s unavailable: %v\n", opts.Config.LLMBaseURL, err)
 14+		fmt.Fprintf(os.Stderr, "persona gen: LLM service at %s unavailable: %v\n", opts.LLMBaseURL, err)
 15 		os.Exit(1)
 16 	}
 17 
 18@@ -179,13 +179,15 @@ func genPersonaCmd(args []string) {
 19 		fmt.Fprintf(os.Stderr, "persona gen: encode draft: %v\n", merr)
 20 		os.Exit(1)
 21 	}
 22-	fmt.Fprintln(os.Stdout, string(out))
 23+	if _, werr := fmt.Fprintln(os.Stdout, string(out)); werr != nil {
 24+		os.Exit(1)
 25+	}
 26 	fmt.Fprintln(os.Stderr, "DRAFT persona. Requires human review before use.")
 27 	fmt.Fprintln(os.Stderr, "Nothing was written to assets/personas/. Review it and save it yourself.")
 28 }
 29 
 30 func usage(w io.Writer) {
 31-	fmt.Fprint(w, `jp - Japanese learning RPG
 32+	_, _ = fmt.Fprint(w, `jp - Japanese learning RPG
 33 
 34 Usage:
 35   jp run [flags]           Run the game
 36diff --git a/internal/availability/availability.go b/internal/availability/availability.go
 37index 4d231532767e317441f5d379612dde7976e06175..7d7f401e0def7d6a20e6bea7e43e9827c7aef4b3 100644
 38--- a/internal/availability/availability.go
 39+++ b/internal/availability/availability.go
 40@@ -46,7 +46,7 @@ func CheckAllAsync(cfg config.Config, fn func(Service)) {
 41 func checkLLM(ctx context.Context, client *http.Client, base string) Service {
 42 	s := Service{Name: "LLM", URL: base}
 43 	modelsURL := strings.TrimRight(base, "/") + "/models"
 44-	resp, body, err := doGet(ctx, client, modelsURL)
 45+	status, body, err := doGet(ctx, client, modelsURL)
 46 	if err != nil {
 47 		s.Detail = err.Error()
 48 		return s
 49@@ -55,7 +55,7 @@ func checkLLM(ctx context.Context, client *http.Client, base string) Service {
 50 	if ids := modelIDs(body); len(ids) > 0 {
 51 		s.Detail = "models: " + strings.Join(ids, ", ")
 52 	} else {
 53-		s.Detail = fmt.Sprintf("HTTP %d", resp.StatusCode)
 54+		s.Detail = fmt.Sprintf("HTTP %d", status)
 55 	}
 56 	return s
 57 }
 58@@ -63,16 +63,16 @@ func checkLLM(ctx context.Context, client *http.Client, base string) Service {
 59 func checkTTS(ctx context.Context, client *http.Client, base string) Service {
 60 	s := Service{Name: "TTS", URL: base}
 61 	modelsURL := strings.TrimRight(base, "/") + "/models"
 62-	resp, _, err := doGet(ctx, client, modelsURL)
 63+	status, _, err := doGet(ctx, client, modelsURL)
 64 	if err != nil {
 65 		s.Detail = err.Error()
 66 		return s
 67 	}
 68 	s.Up = true
 69-	if resp.StatusCode == http.StatusNotFound {
 70+	if status == http.StatusNotFound {
 71 		s.Detail = "server responded; /models not available (HTTP 404)"
 72 	} else {
 73-		s.Detail = fmt.Sprintf("HTTP %d", resp.StatusCode)
 74+		s.Detail = fmt.Sprintf("HTTP %d", status)
 75 	}
 76 	return s
 77 }
 78@@ -84,32 +84,33 @@ func checkSTT(ctx context.Context, client *http.Client, sttURL string) Service {
 79 		s.Detail = err.Error()
 80 		return s
 81 	}
 82-	resp, _, err := doGet(ctx, client, root)
 83+	status, _, err := doGet(ctx, client, root)
 84 	if err != nil {
 85 		s.Detail = err.Error()
 86 		return s
 87 	}
 88 	s.Up = true
 89-	s.Detail = fmt.Sprintf("HTTP %d", resp.StatusCode)
 90+	s.Detail = fmt.Sprintf("HTTP %d", status)
 91 	return s
 92 }
 93 
 94-// doGet issues a bounded GET and returns the response plus its fully read body.
 95-func doGet(ctx context.Context, client *http.Client, target string) (*http.Response, []byte, error) {
 96+// doGet issues a bounded GET and returns the status code plus the fully read
 97+// body.
 98+func doGet(ctx context.Context, client *http.Client, target string) (int, []byte, error) {
 99 	req, err := http.NewRequestWithContext(ctx, http.MethodGet, target, nil)
100 	if err != nil {
101-		return nil, nil, err
102+		return 0, nil, err
103 	}
104 	resp, err := client.Do(req)
105 	if err != nil {
106-		return nil, nil, err
107+		return 0, nil, err
108 	}
109-	defer resp.Body.Close()
110+	defer func() { _ = resp.Body.Close() }()
111 	body, readErr := io.ReadAll(resp.Body)
112 	if readErr != nil {
113-		return resp, nil, readErr
114+		return 0, nil, readErr
115 	}
116-	return resp, body, nil
117+	return resp.StatusCode, body, nil
118 }
119 
120 // hostRoot reduces a full inference URL to its scheme://host/ so the STT check
121diff --git a/internal/llm/client.go b/internal/llm/client.go
122index 31b20d4cd2ddd044f0ec694b67fdf2db2e125d55..fc6551c9454fb7afcd17a950b329ea6782e9c5cc 100644
123--- a/internal/llm/client.go
124+++ b/internal/llm/client.go
125@@ -101,7 +101,7 @@ func (c *Client) Generate(ctx context.Context, msgs []Message, opts Options) (st
126 	if err != nil {
127 		return "", fmt.Errorf("llm: request to %s: %w", url, err)
128 	}
129-	defer resp.Body.Close()
130+	defer func() { _ = resp.Body.Close() }()
131 
132 	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
133 		detail, _ := io.ReadAll(io.LimitReader(resp.Body, 4096))
134diff --git a/internal/stt/whisper.go b/internal/stt/whisper.go
135index 51707374635383736ef5d5bf7b0f92f29e9651e9..9a69be166e7c955e465219d3a4ae75270cce14ec 100644
136--- a/internal/stt/whisper.go
137+++ b/internal/stt/whisper.go
138@@ -37,7 +37,7 @@ func (c *WhisperClient) Transcribe(ctx context.Context, wavPath string) (string,
139 	if err != nil {
140 		return "", fmt.Errorf("stt: read recording %s: %w", wavPath, err)
141 	}
142-	defer os.Remove(wavPath)
143+	defer func() { _ = os.Remove(wavPath) }()
144 
145 	body, contentType, err := encodeMultipart(data, c.Language)
146 	if err != nil {
147@@ -53,7 +53,7 @@ func (c *WhisperClient) Transcribe(ctx context.Context, wavPath string) (string,
148 	if err != nil {
149 		return "", fmt.Errorf("stt: request to %s: %w", c.URL, err)
150 	}
151-	defer resp.Body.Close()
152+	defer func() { _ = resp.Body.Close() }()
153 
154 	raw, err := io.ReadAll(resp.Body)
155 	if err != nil {
156diff --git a/internal/tts/client.go b/internal/tts/client.go
157index c3bb07839f16c18485a9bff5ac451dc81d088424..6c28149a94513e31d299d09061f6f1470127789f 100644
158--- a/internal/tts/client.go
159+++ b/internal/tts/client.go
160@@ -70,7 +70,7 @@ func (c *Client) Speech(ctx context.Context, kana string) ([]byte, error) {
161 	if err != nil {
162 		return nil, fmt.Errorf("tts: request to %s: %w", url, err)
163 	}
164-	defer resp.Body.Close()
165+	defer func() { _ = resp.Body.Close() }()
166 
167 	raw, err := io.ReadAll(resp.Body)
168 	if err != nil {
169diff --git a/internal/tts/player.go b/internal/tts/player.go
170index d603e58dd1adce103497bdf359f7222e6c5c03f9..de4b16c55a8a99f6277122b6fa8bfaa849f168f6 100644
171--- a/internal/tts/player.go
172+++ b/internal/tts/player.go
173@@ -14,12 +14,12 @@ import (
174 // later clips are played through that same context (oto supports a single
175 // context). Play validates the WAV synchronously and returns any error from
176 // that check; device work happens off the calling goroutine so the TUI event
177-// loop is never blocked. A new Play interrupts an in-flight playback, and Stop
178-// interrupts one explicitly.
179+// loop is never blocked. A new Play interrupts an in-flight playback.
180 //
181 // Each Play takes an onDone callback that fires exactly once when that clip
182-// finishes playing normally. An interrupted clip (a newer Play, or Stop) never
183-// fires onDone, so callers can distinguish "played to the end" from "cut off".
184+// finishes playing normally. An interrupted clip (superseded by a newer Play)
185+// never fires onDone, so callers can distinguish "played to the end" from
186+// "cut off".
187 type Player struct {
188 	mu      sync.Mutex
189 	ctx     *oto.Context
190@@ -84,12 +84,10 @@ func (p *Player) play(ctx context.Context, spec *WAVSpec, onDone func()) {
191 		select {
192 		case <-ctx.Done():
193 			pl.PauseAndStopReading()
194-			pl.Close()
195 			return
196 		case <-time.After(20 * time.Millisecond):
197 		}
198 	}
199-	pl.Close()
200 	finish()
201 }
202