Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 38 additions & 3 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,62 @@ run:
tests: true
linters:
enable:
- asasalint
- asciicheck
- bidichk
- containedctx
- copyloopvar
- decorder
- depguard
- dogsled
- durationcheck
- errcheck
- errname
- errorlint
- exptostd
- fatcontext
- forbidigo
- ginkgolinter
- gocheckcompilerdirectives
- gochecknoinits
- gochecksumtype
- gocritic
- gomoddirectives
- gomodguard
- goprintffuncname
- govet
- grouper
- iface
- importas # Enforces consistent import aliases.
- inamedparam
- ineffassign
- intrange
- iotamixing
- loggercheck
- misspell
- mirror
- nakedret
- nolintlint
- nosprintfhostport
- nilnesserr
- predeclared
- reassign
- recvcheck
- revive
- rowserrcheck
- sloglint
- staticcheck
- testableexamples
- testifylint
- thelper
- unconvert
- unparam
- unused
- usestdlibvars
- forbidigo
- iotamixing
- gochecknoinits
- unqueryvet
- usetesting
- whitespace
- wastedassign
settings:
forbidigo:
forbid:
Expand Down Expand Up @@ -63,6 +95,9 @@ linters:
deny:
- pkg: github.com/stretchr/testify
desc: don't use testify in production code
gomoddirectives:
replace-allow-list:
- github.com/charmbracelet/ultraviolet
gocritic:
disabled-checks:
- dupImport
Expand Down
4 changes: 3 additions & 1 deletion cmd/root/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package root

import (
"context"
"errors"
"fmt"
"io"
"log/slog"
Expand Down Expand Up @@ -422,7 +423,8 @@ func (f *runExecFlags) handleExecMode(ctx context.Context, out *cli.Printer, rt
OutputJSON: f.outputJSON,
AutoApprove: f.autoApprove,
}, rt, sess, execArgs)
if cliErr, ok := err.(cli.RuntimeError); ok {
var cliErr cli.RuntimeError
if errors.As(err, &cliErr) {
return RuntimeError{Err: cliErr.Err}
}
return err
Expand Down
2 changes: 1 addition & 1 deletion pkg/app/transcript/transcript.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func toJSONString(builder *strings.Builder, in string) {
if err := json.Unmarshal([]byte(in), &content); err == nil {
if formatted, err := json.MarshalIndent(content, "", " "); err == nil {
builder.WriteString("```json\n")
builder.WriteString(string(formatted))
builder.Write(formatted)
builder.WriteString("\n```\n")
} else {
builder.WriteString(in)
Expand Down
6 changes: 3 additions & 3 deletions pkg/config/auto.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ var cloudProviders = []providerConfig{
}, "AWS_ACCESS_KEY_ID (or AWS_PROFILE, AWS_ROLE_ARN, AWS_BEARER_TOKEN_BEDROCK)"},
}

// ErrAutoModelFallback is returned when auto model selection fails because
// AutoModelFallbackError is returned when auto model selection fails because
// no providers are available (no API keys configured and DMR not installed).
type ErrAutoModelFallback struct{}
type AutoModelFallbackError struct{}

func (e *ErrAutoModelFallback) Error() string {
func (e *AutoModelFallbackError) Error() string {
var hints []string
for _, p := range cloudProviders {
hints = append(hints, fmt.Sprintf(" - %s: %s", p.name, p.hint))
Expand Down
4 changes: 3 additions & 1 deletion pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,9 @@ func TestCheckRequiredEnvVars(t *testing.T) {
require.NoError(t, err)
} else {
require.Error(t, err)
assert.Equal(t, test.expectedMissing, err.(*environment.RequiredEnvError).Missing)
var reqErr *environment.RequiredEnvError
require.ErrorAs(t, err, &reqErr)
assert.Equal(t, test.expectedMissing, reqErr.Missing)
}
})
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/config/latest/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ type SandboxConfig struct {
// DeferConfig represents the deferred loading configuration for a toolset.
// It can be either a boolean (true to defer all tools) or a slice of strings
// (list of tool names to defer).
type DeferConfig struct {
type DeferConfig struct { //nolint:recvcheck // MarshalYAML must use value receiver for YAML slice encoding, UnmarshalYAML must use pointer
// DeferAll is true when all tools should be deferred
DeferAll bool `json:"-"`
// Tools is the list of specific tool names to defer (empty if DeferAll is true)
Expand Down Expand Up @@ -635,7 +635,7 @@ func (c *RAGConfig) GetRespectVCS() bool {

// RAGStrategyConfig represents a single retrieval strategy configuration
// Strategy-specific fields are stored in Params (validated by strategy implementation)
type RAGStrategyConfig struct {
type RAGStrategyConfig struct { //nolint:recvcheck // Marshal methods must use value receiver for YAML/JSON slice encoding, Unmarshal must use pointer
Type string `json:"type"` // Strategy type: "chunked-embeddings", "bm25", etc.
Docs []string `json:"docs,omitempty"` // Strategy-specific documents (augments shared docs)
Database RAGDatabaseConfig `json:"database,omitempty"` // Database configuration
Expand Down
2 changes: 1 addition & 1 deletion pkg/config/types/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func (c *Commands) UnmarshalYAML(unmarshal func(any) error) error {

// parseCommandValue parses a command value which can be either:
// - a simple string (becomes the instruction)
// - a map with description/instruction fields
// - a map with description/instruction fields.
func parseCommandValue(v any) (Command, error) {
switch val := v.(type) {
case string:
Expand Down
4 changes: 2 additions & 2 deletions pkg/config/v0/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

const Version = "0"

// Toolset represents a tool configuration
// Toolset represents a tool configuration.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol this is really pedantic tbh

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I need to take a look again. I want to catch issues. not this

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only a couple of comments were invalid. Let's try to live with it and revisit

type Toolset struct {
Type string `json:"type,omitempty" yaml:"type,omitempty"`
Command string `json:"command,omitempty" yaml:"command,omitempty"`
Expand All @@ -25,7 +25,7 @@ type Remote struct {
Headers map[string]string `json:"headers,omitempty" yaml:"headers,omitempty"`
}

// Ensure that either Command or Remote is set, but not both empty
// Ensure that either Command or Remote is set, but not both empty.
func (t *Toolset) validate() error {
if t.Type != "mcp" {
return nil
Expand Down
2 changes: 1 addition & 1 deletion pkg/config/v2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ type RAGConfig struct {

// RAGStrategyConfig represents a single retrieval strategy configuration
// Strategy-specific fields are stored in Params (validated by strategy implementation)
type RAGStrategyConfig struct {
type RAGStrategyConfig struct { //nolint:recvcheck // Marshal methods must use value receiver for YAML/JSON slice encoding, Unmarshal must use pointer
Type string `json:"type"` // Strategy type: "chunked-embeddings", "bm25", etc.
Docs []string `json:"docs,omitempty"` // Strategy-specific documents (augments shared docs)
Database RAGDatabaseConfig `json:"database,omitempty"` // Database configuration
Expand Down
4 changes: 2 additions & 2 deletions pkg/config/v3/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ type SandboxConfig struct {
// DeferConfig represents the deferred loading configuration for a toolset.
// It can be either a boolean (true to defer all tools) or a slice of strings
// (list of tool names to defer).
type DeferConfig struct {
type DeferConfig struct { //nolint:recvcheck // MarshalYAML must use value receiver for YAML slice encoding, UnmarshalYAML must use pointer
// DeferAll is true when all tools should be deferred
DeferAll bool `json:"-"`
// Tools is the list of specific tool names to defer (empty if DeferAll is true)
Expand Down Expand Up @@ -381,7 +381,7 @@ func (c *RAGConfig) GetRespectVCS() bool {

// RAGStrategyConfig represents a single retrieval strategy configuration
// Strategy-specific fields are stored in Params (validated by strategy implementation)
type RAGStrategyConfig struct {
type RAGStrategyConfig struct { //nolint:recvcheck // Marshal methods must use value receiver for YAML/JSON slice encoding, Unmarshal must use pointer
Type string `json:"type"` // Strategy type: "chunked-embeddings", "bm25", etc.
Docs []string `json:"docs,omitempty"` // Strategy-specific documents (augments shared docs)
Database RAGDatabaseConfig `json:"database,omitempty"` // Database configuration
Expand Down
6 changes: 3 additions & 3 deletions pkg/environment/keychain.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import (
// via the `security` command-line tool.
type KeychainProvider struct{}

type ErrKeychainNotAvailable struct{}
type KeychainNotAvailableError struct{}

func (ErrKeychainNotAvailable) Error() string {
func (KeychainNotAvailableError) Error() string {
return "security command is not available (macOS keychain access)"
}

Expand All @@ -27,7 +27,7 @@ func NewKeychainProvider() (*KeychainProvider, error) {
slog.Warn("failed to lookup `security` binary", "error", err)
}
if path == "" {
return nil, ErrKeychainNotAvailable{}
return nil, KeychainNotAvailableError{}
}
return &KeychainProvider{}, nil
}
Expand Down
6 changes: 3 additions & 3 deletions pkg/environment/pass.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import (
// manager.
type PassProvider struct{}

type ErrPassNotAvailable struct{}
type PassNotAvailableError struct{}

func (ErrPassNotAvailable) Error() string {
func (PassNotAvailableError) Error() string {
return "pass is not installed"
}

Expand All @@ -26,7 +26,7 @@ func NewPassProvider() (*PassProvider, error) {
slog.Warn("failed to lookup `pass` binary", "error", err)
}
if path == "" {
return nil, ErrPassNotAvailable{}
return nil, PassNotAvailableError{}
}
return &PassProvider{}, nil
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/evaluation/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ func (r *Runner) preBuildImages(ctx context.Context, out io.Writer, evals []Inpu
}

if len(errs) > 0 {
return fmt.Errorf("failed to build %d image(s): %v", len(errs), errs[0])
return fmt.Errorf("failed to build %d image(s): %w", len(errs), errs[0])
}

return nil
Expand Down
3 changes: 2 additions & 1 deletion pkg/fake/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"bufio"
"bytes"
"context"
"errors"
"fmt"
"io"
"log/slog"
Expand Down Expand Up @@ -428,7 +429,7 @@ func StreamCopy(c echo.Context, resp *http.Response) error {
}
if result.err != nil {
// io.EOF or context canceled means normal completion
if result.err == io.EOF || ctx.Err() != nil {
if errors.Is(result.err, io.EOF) || ctx.Err() != nil {
return nil
}
slog.ErrorContext(ctx, "stream read error", "error", result.err)
Expand Down
3 changes: 2 additions & 1 deletion pkg/fsx/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package fsx

import (
"context"
"errors"
"io/fs"
"os"
"path/filepath"
Expand Down Expand Up @@ -209,7 +210,7 @@ func WalkFiles(ctx context.Context, root string, opts WalkFilesOptions) ([]strin
return nil
})

if err != nil && err != context.Canceled && err != context.DeadlineExceeded {
if err != nil && !errors.Is(err, context.Canceled) && !errors.Is(err, context.DeadlineExceeded) {
return files, err
}

Expand Down
4 changes: 3 additions & 1 deletion pkg/hooks/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"cmp"
"context"
"encoding/json"
"errors"
"fmt"
"log/slog"
"os"
Expand Down Expand Up @@ -264,7 +265,8 @@ func (e *Executor) executeHook(ctx context.Context, hook Hook, inputJSON []byte)

exitCode := 0
if err != nil {
if exitErr, ok := err.(*exec.ExitError); ok {
var exitErr *exec.ExitError
if errors.As(err, &exitErr) {
exitCode = exitErr.ExitCode()
} else {
return nil, stdout.String(), stderr.String(), -1, err
Expand Down
3 changes: 2 additions & 1 deletion pkg/mcp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package mcp
import (
"cmp"
"context"
"errors"
"fmt"
"log/slog"
"net"
Expand Down Expand Up @@ -74,7 +75,7 @@ func StartHTTPServer(ctx context.Context, agentFilename, agentName string, runCo
case <-ctx.Done():
return httpServer.Shutdown(context.Background())
case err := <-errCh:
if err == http.ErrServerClosed {
if errors.Is(err, http.ErrServerClosed) {
return nil
}
return err
Expand Down
4 changes: 4 additions & 0 deletions pkg/memory/database/sqlite/sqlite.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ func (m *MemoryDatabase) GetMemories(ctx context.Context) ([]database.UserMemory
memories = append(memories, memory)
}

if err := rows.Err(); err != nil {
return nil, err
}

return memories, nil
}

Expand Down
3 changes: 2 additions & 1 deletion pkg/model/provider/custom_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package provider
import (
"context"
"encoding/json"
"errors"
"io"
"net/http"
"net/http/httptest"
Expand Down Expand Up @@ -502,7 +503,7 @@ func drainStream(t *testing.T, stream chat.MessageStream) {
t.Helper()
for {
_, err := stream.Recv()
if err == io.EOF {
if errors.Is(err, io.EOF) {
return
}
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions pkg/model/provider/dmr/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,13 +193,13 @@ func getDMRFallbackURLs(containerized bool) []string {
// Inside a container: try Docker internal hostnames and bridge gateway
return []string{
fmt.Sprintf("http://%s%s/v1/", dmrModelRunnerInternal, dmrInferencePrefix),
fmt.Sprintf("http://%s:%s%s/v1/", dmrHostDockerInternal, dmrDefaultPort, dmrInferencePrefix),
fmt.Sprintf("http://%s:%s%s/v1/", dmrDockerBridgeGateway, dmrDefaultPort, dmrInferencePrefix),
"http://" + net.JoinHostPort(dmrHostDockerInternal, dmrDefaultPort) + dmrInferencePrefix + "/v1/",
"http://" + net.JoinHostPort(dmrDockerBridgeGateway, dmrDefaultPort) + dmrInferencePrefix + "/v1/",
}
}
// On the host: only localhost makes sense as a fallback
return []string{
fmt.Sprintf("http://%s:%s%s/v1/", dmrLocalhost, dmrDefaultPort, dmrInferencePrefix),
"http://" + net.JoinHostPort(dmrLocalhost, dmrDefaultPort) + dmrInferencePrefix + "/v1/",
}
}

Expand Down
3 changes: 2 additions & 1 deletion pkg/rag/strategy/bm25_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package strategy
import (
"context"
"database/sql"
"errors"
"fmt"
"log/slog"
"os"
Expand Down Expand Up @@ -96,7 +97,7 @@ func (d *bm25DB) AddDocument(ctx context.Context, doc database.Document) error {
fmt.Sprintf("SELECT 1 FROM %s WHERE source_path = ? AND chunk_index = ?", d.docsTable),
doc.SourcePath, doc.ChunkIndex).Scan(&exists)

if err != nil && err != sql.ErrNoRows {
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return fmt.Errorf("failed to check existing document: %w", err)
}

Expand Down
3 changes: 2 additions & 1 deletion pkg/runtime/connectrpc_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package runtime
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"log/slog"
Expand Down Expand Up @@ -241,7 +242,7 @@ func (c *ConnectRPCClient) runAgentWithAgentName(ctx context.Context, sessionID,
}
}

if err := stream.Err(); err != nil && err != io.EOF {
if err := stream.Err(); err != nil && !errors.Is(err, io.EOF) {
slog.Error("Stream error", "error", err)
eventChan <- Error(fmt.Sprintf("stream error: %v", err))
}
Expand Down
Loading
Loading