style: fix remaining lint errors (misspell, shadow, unused, etc.)

- Fix British→American spelling (cancelled→canceled, honour→honor, etc.)
- Remove unused loadSkills method and regex vars
- Fix variable shadowing (err, max)
- Add explicit returns for nakedret
- Use net.JoinHostPort for nosprintfhostport
- Preallocate slices, add nolint:gosmopolitan for CJK test data
- Fix golines and trailing whitespace

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
dj-oyu 2026-03-01 00:22:14 +09:00
parent b90f49970e
commit d8f00d4148
15 changed files with 55 additions and 69 deletions

View file

@ -4,11 +4,13 @@ import (
"context"
"fmt"
"log"
"net"
"net/http"
"os"
"os/exec"
"os/signal"
"path/filepath"
"strconv"
"strings"
"time"
@ -216,7 +218,8 @@ func gatewayCmd(debug bool, orchestration bool) error {
if certErr != nil {
logger.ErrorCF("miniapp", "Failed to fetch TLS cert", map[string]any{"error": certErr.Error()})
} else {
webAppURL = fmt.Sprintf("https://%s:%d/miniapp", hostname, cfg.Gateway.Port)
hostPort := net.JoinHostPort(hostname, strconv.Itoa(cfg.Gateway.Port))
webAppURL = "https://" + hostPort + "/miniapp"
cfg.Channels.Telegram.WebAppURL = webAppURL
tlsCert, tlsKey = certFile, keyFile
useTLS = true
@ -268,7 +271,10 @@ func gatewayCmd(debug bool, orchestration bool) error {
cfg.Gateway.Port,
)
} else {
fmt.Printf("✓ Health endpoints available at http://%s:%d/health and /ready\n", cfg.Gateway.Host, cfg.Gateway.Port)
fmt.Printf(
"✓ Health endpoints available at http://%s:%d/health and /ready\n",
cfg.Gateway.Host, cfg.Gateway.Port,
)
}
go agentLoop.Run(ctx)

View file

@ -787,25 +787,6 @@ func (cb *ContextBuilder) AddAssistantMessage(
return messages
}
func (cb *ContextBuilder) loadSkills() string {
allSkills := cb.skillsLoader.ListSkills()
if len(allSkills) == 0 {
return ""
}
var skillNames []string
for _, s := range allSkills {
skillNames = append(skillNames, s.Name)
}
content := cb.skillsLoader.LoadSkillsForContext(skillNames)
if content == "" {
return ""
}
return "# Skill Definitions\n\n" + content
}
// LoadSkill loads a skill by name, returning its content (with frontmatter stripped) and whether it was found.
func (cb *ContextBuilder) LoadSkill(name string) (string, bool) {
return cb.skillsLoader.LoadSkill(name)

View file

@ -645,7 +645,8 @@ func (al *AgentLoop) processMessage(ctx context.Context, msg bus.InboundMessage)
lower := strings.ToLower(content)
// Check for stop keywords
stopKeywords := []string{"stop", "cancel", "abort", "停止", "中止", "やめて"} //nolint:gosmopolitan // intentional CJK stop words
//nolint:gosmopolitan // intentional CJK stop words
stopKeywords := []string{"stop", "cancel", "abort", "停止", "中止", "やめて"}
isStop := false
for _, kw := range stopKeywords {
if lower == kw {
@ -1999,13 +2000,13 @@ func (al *AgentLoop) runLLMIteration(
if sp, ok := p.(providers.StreamingProvider); ok && sp.CanStream() {
streamCtx, streamCancel := context.WithCancel(ctx)
defer streamCancel()
ch, err := sp.ChatStream(streamCtx, messages, providerToolDefs, model, opts_)
if err != nil {
return nil, err
ch, sErr := sp.ChatStream(streamCtx, messages, providerToolDefs, model, opts_)
if sErr != nil {
return nil, sErr
}
resp, repetition, err := consumeStreamWithRepetitionDetection(ch, streamCancel, 1000, onChunk)
if err != nil {
return nil, err
resp, repetition, sErr := consumeStreamWithRepetitionDetection(ch, streamCancel, 1000, onChunk)
if sErr != nil {
return nil, sErr
}
if repetition {
resp.FinishReason = "repetition_detected"
@ -2156,7 +2157,7 @@ func (al *AgentLoop) runLLMIteration(
// blocks so loops inside <think> are caught). Skip when the
// provider already returned native tool calls.
// Streaming providers may have already flagged repetition via
// FinishReason="repetition_detected" — honour that too.
// FinishReason="repetition_detected" — honor that too.
if response.FinishReason == "repetition_detected" ||
(len(response.ToolCalls) == 0 && utils.DetectRepetitionLoop(response.Content)) {
logger.WarnCF("agent", "Repetition loop detected in LLM response, retrying",
@ -2603,7 +2604,6 @@ func (al *AgentLoop) runLLMIteration(
al.lastSystemPrompt.Store(newPrompt)
al.promptDirty.Store(false)
}
}
// If max iterations exhausted with tool calls still pending,
@ -2783,7 +2783,7 @@ func (al *AgentLoop) GetPlanInfo() (hasPlan bool, status string, currentPhase, t
totalPhases = mem.GetTotalPhases()
display = mem.FormatPlanDisplay()
memory = mem.ReadLongTerm()
return
return hasPlan, status, currentPhase, totalPhases, display, memory
}
// GetPlanStatus returns the current plan status ("interviewing", "executing", "review", etc.) or "".
@ -2837,7 +2837,7 @@ func (al *AgentLoop) GetContextInfo() (workDir, planWorkDir, workspace string, b
workDir = agent.ContextBuilder.workDir
}
bootstrap = agent.ContextBuilder.ResolveBootstrapPaths()
return
return workDir, planWorkDir, workspace, bootstrap
}
// GetSystemPrompt returns the system prompt last sent to the LLM.

View file

@ -2513,8 +2513,8 @@ func TestAgentLoop_PlanModel_UsedDuringInterviewing(t *testing.T) {
os.MkdirAll(memoryDir, 0o755)
memoryPath := filepath.Join(memoryDir, "MEMORY.md")
memoryContent := "# Active Plan\n\n> Task: Test plan model\n> Status: interviewing\n> Phase: 1\n"
if err := os.WriteFile(memoryPath, []byte(memoryContent), 0o644); err != nil {
t.Fatalf("Failed to write MEMORY.md: %v", err)
if wErr := os.WriteFile(memoryPath, []byte(memoryContent), 0o644); wErr != nil {
t.Fatalf("Failed to write MEMORY.md: %v", wErr)
}
_, err = al.ProcessDirectWithChannel(
@ -2581,8 +2581,8 @@ func TestAgentLoop_PlanModel_NotUsedDuringExecuting(t *testing.T) {
## Phase 1: Build
- [ ] Run build
`
if err := os.WriteFile(memoryPath, []byte(memoryContent), 0o644); err != nil {
t.Fatalf("Failed to write MEMORY.md: %v", err)
if wErr := os.WriteFile(memoryPath, []byte(memoryContent), 0o644); wErr != nil {
t.Fatalf("Failed to write MEMORY.md: %v", wErr)
}
_, err = al.ProcessDirectWithChannel(
@ -2642,8 +2642,8 @@ func TestAgentLoop_PlanModel_ResolvesProviderForSingleCandidate(t *testing.T) {
os.MkdirAll(memoryDir, 0o755)
memoryPath := filepath.Join(memoryDir, "MEMORY.md")
memoryContent := "# Active Plan\n\n> Task: Test provider resolution\n> Status: interviewing\n> Phase: 1\n"
if err := os.WriteFile(memoryPath, []byte(memoryContent), 0o644); err != nil {
t.Fatalf("Failed to write MEMORY.md: %v", err)
if wErr := os.WriteFile(memoryPath, []byte(memoryContent), 0o644); wErr != nil {
t.Fatalf("Failed to write MEMORY.md: %v", wErr)
}
_, err = al.ProcessDirectWithChannel(

View file

@ -146,8 +146,6 @@ var (
reStatus = regexp.MustCompile(`(?m)^> Status:\s*(.+)`)
rePhase = regexp.MustCompile(`(?m)^> Phase:\s*(\d+)`)
rePhaseHeader = regexp.MustCompile(`(?m)^## Phase (\d+):\s*(.*)`)
reStepDone = regexp.MustCompile(`(?m)^- \[x\] `)
reStepTodo = regexp.MustCompile(`(?m)^- \[ \] `)
reWorkDir = regexp.MustCompile(`(?m)^> WorkDir:\s*(.+)`)
)
@ -182,16 +180,16 @@ func (ms *MemoryStore) GetCurrentPhase() int {
func (ms *MemoryStore) GetTotalPhases() int {
content := ms.ReadLongTerm()
matches := rePhaseHeader.FindAllStringSubmatch(content, -1)
max := 0
maxN := 0
for _, m := range matches {
if len(m) >= 2 {
n, _ := strconv.Atoi(m[1])
if n > max {
max = n
if n > maxN {
maxN = n
}
}
}
return max
return maxN
}
// IsPlanComplete returns true if all steps in all phases are [x].
@ -638,16 +636,16 @@ func (ms *MemoryStore) getPlanContextFrom(content string) string {
// maxPhaseNumber returns the highest phase number found in content.
func maxPhaseNumber(content string) int {
matches := rePhaseHeader.FindAllStringSubmatch(content, -1)
max := 0
maxN := 0
for _, m := range matches {
if len(m) >= 2 {
n, _ := strconv.Atoi(m[1])
if n > max {
max = n
if n > maxN {
maxN = n
}
}
}
return max
return maxN
}
// getPhaseTitle extracts the title of a phase from "## Phase N: Title".

View file

@ -26,7 +26,7 @@ import (
// buildInitData constructs a valid initData string from params and a bot token.
func buildInitData(params map[string]string, botToken string) string {
// Build data-check-string
var pairs []string
pairs := make([]string, 0, len(params))
for k, v := range params {
pairs = append(pairs, fmt.Sprintf("%s=%s", k, v))
}

View file

@ -19,7 +19,7 @@ type Event struct {
From string `json:"from,omitempty"`
To string `json:"to,omitempty"`
Text string `json:"text,omitempty"`
Reason string `json:"reason,omitempty"` // agent_gc: completed | failed | cancelled
Reason string `json:"reason,omitempty"` // agent_gc: completed | failed | canceled
Created int64 `json:"created,omitempty"`
}

View file

@ -1086,8 +1086,9 @@ func TestExtractXMLToolCalls_MismatchedCloseTag(t *testing.T) {
}
}
func TestStripXMLToolCalls_MismatchedCloseTag(t *testing.T) { //nolint:gosmopolitan // CJK test data
text := `今テスト走らせるね
func TestStripXMLToolCalls_MismatchedCloseTag(t *testing.T) {
text := `今テスト走らせるね。` + //nolint:gosmopolitan // CJK test data
`
<minimax:toolcall>
<invoke name="exec">
<parameter name="command">cd /home/user && pytest</parameter>
@ -1098,7 +1099,7 @@ func TestStripXMLToolCalls_MismatchedCloseTag(t *testing.T) { //nolint:gosmopoli
if strings.Contains(got, "toolcall") || strings.Contains(got, "tool_call") {
t.Errorf("should remove XML block, got %q", got)
}
if !strings.Contains(got, "今テスト走らせるね。") {
if !strings.Contains(got, "今テスト走らせるね。") { //nolint:gosmopolitan // CJK test data
t.Errorf("should keep text before, got %q", got)
}
}
@ -1163,7 +1164,7 @@ Finished.`
func TestExtractXMLToolCalls_OrphanedClosingTag(t *testing.T) {
// LLM emits [TOOLCALL] marker + <invoke> with orphaned closing tag (no opening tag)
text := "了解!確認するね。\n[TOOLCALL]\n<invoke name=\"listdir\">\n<parameter name=\"path\">/home/user/workspace</parameter>\n</invoke>\n</minimax:tool_call>"
text := "了解!確認するね。\n[TOOLCALL]\n<invoke name=\"listdir\">\n<parameter name=\"path\">/home/user/workspace</parameter>\n</invoke>\n</minimax:tool_call>" //nolint:gosmopolitan // CJK test data
calls := extractXMLToolCalls(text)
if len(calls) != 1 {
@ -1178,12 +1179,12 @@ func TestExtractXMLToolCalls_OrphanedClosingTag(t *testing.T) {
}
func TestStripXMLToolCalls_OrphanedClosingTag(t *testing.T) {
text := "了解!確認するね。\n[TOOLCALL]\n<invoke name=\"listdir\">\n<parameter name=\"path\">/home/user</parameter>\n</invoke>\n</minimax:tool_call>"
text := "了解!確認するね。\n[TOOLCALL]\n<invoke name=\"listdir\">\n<parameter name=\"path\">/home/user</parameter>\n</invoke>\n</minimax:tool_call>" //nolint:gosmopolitan // CJK test data
got := stripXMLToolCalls(text)
if strings.Contains(got, "invoke") || strings.Contains(got, "TOOLCALL") || strings.Contains(got, "minimax") {
t.Errorf("should remove orphaned closing tag block, got %q", got)
}
if !strings.Contains(got, "了解") {
if !strings.Contains(got, "了解") { //nolint:gosmopolitan // CJK test data
t.Errorf("should keep user-facing text, got %q", got)
}
}

View file

@ -259,7 +259,7 @@ func (p *Provider) CanStream() bool {
// ChatStream opens an SSE connection and returns a channel of StreamEvent.
// The channel is closed when the stream ends or an error occurs.
// Cancelling ctx will abort the HTTP request and close the channel.
// Canceling ctx will abort the HTTP request and close the channel.
func (p *Provider) ChatStream(
ctx context.Context,
messages []Message,
@ -294,7 +294,7 @@ func (p *Provider) ChatStream(
}
// readSSEIntoChannel reads SSE lines from r and sends StreamEvent values on ch.
// It returns when the stream ends, an error occurs, or ctx is cancelled.
// It returns when the stream ends, an error occurs, or ctx is canceled.
func readSSEIntoChannel(ctx context.Context, r io.Reader, ch chan<- protocoltypes.StreamEvent) {
scanner := bufio.NewScanner(r)
scanner.Buffer(make([]byte, 0, 64*1024), 1024*1024)

View file

@ -519,7 +519,7 @@ func TestReadSSEIntoChannel_TextAndToolCalls(t *testing.T) {
}
func TestReadSSEIntoChannel_ContextCancel(t *testing.T) {
// Simulate a slow SSE stream that gets cancelled.
// Simulate a slow SSE stream that gets canceled.
ctx, cancel := context.WithCancel(context.Background())
// Create a reader that blocks after sending one chunk.

View file

@ -51,7 +51,7 @@ func NewTracker(workspace string) *Tracker {
}
t.load()
// Initialise Since if this is a fresh tracker
// Initialize Since if this is a fresh tracker
if t.stats.Since.IsZero() {
t.stats.Since = time.Now()
}
@ -104,7 +104,7 @@ func (t *Tracker) GetStats() Stats {
return t.stats
}
// Reset zeroes all counters and re-initialises Since.
// Reset zeroes all counters and re-initializes Since.
func (t *Tracker) Reset() {
t.mu.Lock()
defer t.mu.Unlock()

View file

@ -191,7 +191,7 @@ func (t *BgMonitorTool) actionWatch(ctx context.Context, args map[string]any) *T
IsError: true,
}
case <-ctx.Done():
return ErrorResult("watch cancelled")
return ErrorResult("watch canceled")
case <-ticker.C:
// Continue polling
}

View file

@ -65,7 +65,7 @@ func (m *mockDevTargetManager) GetDevTarget() string {
}
func (m *mockDevTargetManager) ListDevTargets() []miniapp.DevTarget {
var out []miniapp.DevTarget
out := make([]miniapp.DevTarget, 0, len(m.targets))
for _, dt := range m.targets {
out = append(out, *dt)
}

View file

@ -10,9 +10,9 @@ import (
"github.com/sipeed/picoclaw/pkg/providers"
)
// blockingProvider blocks inside Chat until the context is cancelled.
// blockingProvider blocks inside Chat until the context is canceled.
// The ready channel is closed the moment Chat is entered, so callers can
// synchronise before cancelling the context.
// synchronize before canceling the context.
type blockingProvider struct {
ready chan struct{}
}
@ -179,14 +179,14 @@ func TestSubagentManager_Spawn_SnapshotLiveDuringExecution(t *testing.T) {
}
// TestSubagentManager_Spawn_CancelledDuringExecution verifies that when the
// context is cancelled while a subagent's LLM call is in progress, the
// context is canceled while a subagent's LLM call is in progress, the
// Broadcaster receives agent_gc with reason="canceled" and the agent is
// removed from the snapshot.
//
// Synchronisation:
// Synchronization:
// 1. blockingProvider.ready is closed when Chat() is entered (goroutine is
// now blocked inside the LLM call).
// 2. Only then is the context cancelled, so there is no race between spawn
// 2. Only then is the context canceled, so there is no race between spawn
// and cancellation.
func TestSubagentManager_Spawn_CancelledDuringExecution(t *testing.T) {
b := orch.NewBroadcaster()

View file

@ -59,7 +59,7 @@ func TestStripThinkBlocks_ClosedThenUnclosed(t *testing.T) {
func TestDetectRepetitionLoop_HighRepetition(t *testing.T) {
// Repeat a short phrase many times → should be detected
phrase := "結構本格的なコード"
phrase := "結構本格的なコード" //nolint:gosmopolitan // CJK test data
repeated := strings.Repeat(phrase, 300)
if !DetectRepetitionLoop(repeated) {
t.Fatal("DetectRepetitionLoop should return true for highly repetitive text")