From 674d491d373d1b43aa74034b08e3cf199f40cd45 Mon Sep 17 00:00:00 2001 From: dj-oyu <68707227+dj-oyu@users.noreply.github.com> Date: Sun, 1 Mar 2026 00:22:14 +0900 Subject: [PATCH] style: fix remaining lint errors (misspell, shadow, unused, etc.) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- cmd/picoclaw/internal/gateway/helpers.go | 10 +++++++-- pkg/agent/context.go | 19 ----------------- pkg/agent/loop.go | 22 ++++++++++---------- pkg/agent/loop_test.go | 12 +++++------ pkg/agent/memory.go | 18 +++++++--------- pkg/miniapp/miniapp_test.go | 2 +- pkg/orch/broadcaster.go | 2 +- pkg/providers/claude_cli_provider_test.go | 13 ++++++------ pkg/providers/openai_compat/provider.go | 4 ++-- pkg/providers/openai_compat/provider_test.go | 2 +- pkg/stats/tracker.go | 4 ++-- pkg/tools/bg_monitor.go | 2 +- pkg/tools/dev_preview_test.go | 2 +- pkg/tools/subagent_reporter_test.go | 10 ++++----- pkg/utils/string_test.go | 2 +- 15 files changed, 55 insertions(+), 69 deletions(-) diff --git a/cmd/picoclaw/internal/gateway/helpers.go b/cmd/picoclaw/internal/gateway/helpers.go index abedbbbd7..f793297c3 100644 --- a/cmd/picoclaw/internal/gateway/helpers.go +++ b/cmd/picoclaw/internal/gateway/helpers.go @@ -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) diff --git a/pkg/agent/context.go b/pkg/agent/context.go index 043cc2e7f..9ab10deb3 100644 --- a/pkg/agent/context.go +++ b/pkg/agent/context.go @@ -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) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 9c2a80088..09c6604b5 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -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 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. diff --git a/pkg/agent/loop_test.go b/pkg/agent/loop_test.go index 96f3e7af5..b1765f7c4 100644 --- a/pkg/agent/loop_test.go +++ b/pkg/agent/loop_test.go @@ -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( diff --git a/pkg/agent/memory.go b/pkg/agent/memory.go index ce6147e25..7245f3952 100644 --- a/pkg/agent/memory.go +++ b/pkg/agent/memory.go @@ -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". diff --git a/pkg/miniapp/miniapp_test.go b/pkg/miniapp/miniapp_test.go index c4fa2472f..f1dc1e74a 100644 --- a/pkg/miniapp/miniapp_test.go +++ b/pkg/miniapp/miniapp_test.go @@ -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)) } diff --git a/pkg/orch/broadcaster.go b/pkg/orch/broadcaster.go index 9a7d821ba..e5c8b85f8 100644 --- a/pkg/orch/broadcaster.go +++ b/pkg/orch/broadcaster.go @@ -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"` } diff --git a/pkg/providers/claude_cli_provider_test.go b/pkg/providers/claude_cli_provider_test.go index b57f89fd2..83a3397e1 100644 --- a/pkg/providers/claude_cli_provider_test.go +++ b/pkg/providers/claude_cli_provider_test.go @@ -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 + ` cd /home/user && pytest @@ -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 + with orphaned closing tag (no opening tag) - text := "了解!確認するね。\n[TOOLCALL]\n\n/home/user/workspace\n\n" + text := "了解!確認するね。\n[TOOLCALL]\n\n/home/user/workspace\n\n" //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\n/home/user\n\n" + text := "了解!確認するね。\n[TOOLCALL]\n\n/home/user\n\n" //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) } } diff --git a/pkg/providers/openai_compat/provider.go b/pkg/providers/openai_compat/provider.go index df26c7bb4..2ed956991 100644 --- a/pkg/providers/openai_compat/provider.go +++ b/pkg/providers/openai_compat/provider.go @@ -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) diff --git a/pkg/providers/openai_compat/provider_test.go b/pkg/providers/openai_compat/provider_test.go index 93f71458b..a9b309c40 100644 --- a/pkg/providers/openai_compat/provider_test.go +++ b/pkg/providers/openai_compat/provider_test.go @@ -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. diff --git a/pkg/stats/tracker.go b/pkg/stats/tracker.go index 67b6b3e61..f05eacf23 100644 --- a/pkg/stats/tracker.go +++ b/pkg/stats/tracker.go @@ -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() diff --git a/pkg/tools/bg_monitor.go b/pkg/tools/bg_monitor.go index 429c7c69b..4f9bb9dd1 100644 --- a/pkg/tools/bg_monitor.go +++ b/pkg/tools/bg_monitor.go @@ -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 } diff --git a/pkg/tools/dev_preview_test.go b/pkg/tools/dev_preview_test.go index b6597d50b..01c884777 100644 --- a/pkg/tools/dev_preview_test.go +++ b/pkg/tools/dev_preview_test.go @@ -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) } diff --git a/pkg/tools/subagent_reporter_test.go b/pkg/tools/subagent_reporter_test.go index 8906a5453..f378b3060 100644 --- a/pkg/tools/subagent_reporter_test.go +++ b/pkg/tools/subagent_reporter_test.go @@ -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() diff --git a/pkg/utils/string_test.go b/pkg/utils/string_test.go index a8ee476fd..7b4b54098 100644 --- a/pkg/utils/string_test.go +++ b/pkg/utils/string_test.go @@ -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")