refactor(style): auto-fix golangci-lint issues

Amolith created

Change summary

cmd/lunatask-mcp-server.go | 18 +++++++++---
tools/habits.go            |  1 
tools/tasks.go             | 57 +++++++++++++++++++++++++++++++++++++--
tools/tools.go             | 14 +++++++--
4 files changed, 79 insertions(+), 11 deletions(-)

Detailed changes

cmd/lunatask-mcp-server.go 🔗

@@ -17,7 +17,7 @@ import (
 	"git.sr.ht/~amolith/lunatask-mcp-server/tools"
 )
 
-// Goal represents a Lunatask goal with its name and ID
+// Goal represents a Lunatask goal with its name and ID.
 type Goal struct {
 	Name string `toml:"name"`
 	ID   string `toml:"id"`
@@ -29,7 +29,7 @@ func (g Goal) GetName() string { return g.Name }
 // GetID returns the goal's ID.
 func (g Goal) GetID() string { return g.ID }
 
-// Area represents a Lunatask area with its name, ID, and its goals
+// Area represents a Lunatask area with its name, ID, and its goals.
 type Area struct {
 	Name  string `toml:"name"`
 	ID    string `toml:"id"`
@@ -48,10 +48,11 @@ func (a Area) GetGoals() []tools.GoalProvider {
 	for i, g := range a.Goals {
 		providers[i] = g // Goal implements GoalProvider
 	}
+
 	return providers
 }
 
-// Habit represents a Lunatask habit with its name and ID
+// Habit represents a Lunatask habit with its name and ID.
 type Habit struct {
 	Name string `toml:"name"`
 	ID   string `toml:"id"`
@@ -63,7 +64,7 @@ func (h Habit) GetName() string { return h.Name }
 // GetID returns the habit's ID.
 func (h Habit) GetID() string { return h.ID }
 
-// ServerConfig holds the application's configuration loaded from TOML
+// ServerConfig holds the application's configuration loaded from TOML.
 type ServerConfig struct {
 	Host string `toml:"host"`
 	Port int    `toml:"port"`
@@ -81,12 +82,14 @@ var version = ""
 
 func main() {
 	configPath := "./config.toml"
+
 	for i, arg := range os.Args {
 		switch arg {
 		case "-v", "--version":
 			if version == "" {
 				version = "unknown, build with `just build` or copy/paste the build command from ./justfile"
 			}
+
 			fmt.Println("lunatask-mcp-server:", version)
 			os.Exit(0)
 		case "-c", "--config":
@@ -113,6 +116,7 @@ func main() {
 		if area.Name == "" || area.ID == "" {
 			log.Fatalf("All areas (areas[%d]) must have both a name and id", i)
 		}
+
 		for j, goal := range area.Goals {
 			if goal.Name == "" || goal.ID == "" {
 				log.Fatalf("All goals (areas[%d].goals[%d]) must have both a name and id", i, j)
@@ -131,12 +135,13 @@ func main() {
 	sseServer := server.NewSSEServer(mcpServer, server.WithBaseURL(baseURL))
 	listenAddr := fmt.Sprintf("%s:%d", config.Server.Host, config.Server.Port)
 	log.Printf("SSE server listening on %s (baseURL: %s)", listenAddr, baseURL)
+
 	if err := sseServer.Start(listenAddr); err != nil {
 		log.Fatalf("Server error: %v", err)
 	}
 }
 
-// closeFile properly closes a file, handling any errors
+// closeFile properly closes a file, handling any errors.
 func closeFile(f *os.File) {
 	err := f.Close()
 	if err != nil {
@@ -351,14 +356,17 @@ func createDefaultConfigFile(configPath string) {
 			ID:   "habit-id-placeholder",
 		}},
 	}
+
 	file, err := os.OpenFile(configPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o600)
 	if err != nil {
 		log.Fatalf("Failed to create default config at %s: %v", configPath, err)
 	}
 	defer closeFile(file)
+
 	if err := toml.NewEncoder(file).Encode(defaultConfig); err != nil {
 		log.Fatalf("Failed to encode default config to %s: %v", configPath, err)
 	}
+
 	fmt.Printf("A default config has been created at %s.\nPlease edit it to provide your Lunatask access token, correct area/goal IDs, and your timezone (IANA/Olson format, e.g. 'America/New_York'), then restart the server.\n", configPath)
 	os.Exit(1)
 }

tools/habits.go 🔗

@@ -19,6 +19,7 @@ func (h *Handlers) HandleListHabitsAndActivities(ctx context.Context, request mc
 	for _, habit := range h.config.Habits {
 		fmt.Fprintf(&b, "- %s: %s\n", habit.GetName(), habit.GetID())
 	}
+
 	return &mcp.CallToolResult{
 		Content: []mcp.Content{
 			mcp.TextContent{

tools/tasks.go 🔗

@@ -27,12 +27,15 @@ func (h *Handlers) HandleCreateTask(ctx context.Context, request mcp.CallToolReq
 	}
 
 	var areaFoundProvider AreaProvider
+
 	for _, ap := range h.config.Areas {
 		if ap.GetID() == areaID {
 			areaFoundProvider = ap
+
 			break
 		}
 	}
+
 	if areaFoundProvider == nil {
 		return reportMCPError("Area not found for given area_id")
 	}
@@ -40,15 +43,19 @@ func (h *Handlers) HandleCreateTask(ctx context.Context, request mcp.CallToolReq
 	var goalID *string
 	if goalIDStr, exists := arguments["goal_id"].(string); exists && goalIDStr != "" {
 		found := false
+
 		for _, goal := range areaFoundProvider.GetGoals() {
 			if goal.GetID() == goalIDStr {
 				found = true
+
 				break
 			}
 		}
+
 		if !found {
 			return reportMCPError("Goal not found in specified area for given goal_id")
 		}
+
 		goalID = &goalIDStr
 	}
 
@@ -56,6 +63,7 @@ func (h *Handlers) HandleCreateTask(ctx context.Context, request mcp.CallToolReq
 	if !ok || name == "" {
 		return reportMCPError("Missing or invalid required argument: name")
 	}
+
 	if len(name) > 100 {
 		return reportMCPError("'name' must be 100 characters or fewer")
 	}
@@ -75,6 +83,7 @@ func (h *Handlers) HandleCreateTask(ctx context.Context, request mcp.CallToolReq
 		if !ok {
 			return reportMCPError("Invalid type for 'priority' argument: expected string.")
 		}
+
 		priorityMap := map[string]int{
 			"lowest":  -2,
 			"low":     -1,
@@ -82,10 +91,12 @@ func (h *Handlers) HandleCreateTask(ctx context.Context, request mcp.CallToolReq
 			"high":    1,
 			"highest": 2,
 		}
+
 		translatedPriority, isValid := priorityMap[strings.ToLower(priorityStr)]
 		if !isValid {
 			return reportMCPError(fmt.Sprintf("Invalid 'priority' value: '%s'. Must be one of 'lowest', 'low', 'neutral', 'high', 'highest'.", priorityStr))
 		}
+
 		task.Priority = &translatedPriority
 	}
 
@@ -94,6 +105,7 @@ func (h *Handlers) HandleCreateTask(ctx context.Context, request mcp.CallToolReq
 		if !ok {
 			return reportMCPError("Invalid type for 'eisenhower' argument: expected string.")
 		}
+
 		eisenhowerMap := map[string]int{
 			"uncategorised":                0,
 			"both urgent and important":    1,
@@ -101,10 +113,12 @@ func (h *Handlers) HandleCreateTask(ctx context.Context, request mcp.CallToolReq
 			"important, but not urgent":    3,
 			"neither urgent nor important": 4,
 		}
+
 		translatedEisenhower, isValid := eisenhowerMap[strings.ToLower(eisenhowerStr)]
 		if !isValid {
 			return reportMCPError(fmt.Sprintf("Invalid 'eisenhower' value: '%s'. Must be one of 'uncategorised', 'both urgent and important', 'urgent, but not important', 'important, but not urgent', 'neither urgent nor important'.", eisenhowerStr))
 		}
+
 		task.Eisenhower = &translatedEisenhower
 	}
 
@@ -113,11 +127,13 @@ func (h *Handlers) HandleCreateTask(ctx context.Context, request mcp.CallToolReq
 		if !ok {
 			return reportMCPError("'motivation' must be a string")
 		}
+
 		if motivation != "" {
 			validMotivations := map[string]bool{"must": true, "should": true, "want": true}
 			if !validMotivations[motivation] {
 				return reportMCPError("'motivation' must be one of 'must', 'should', or 'want'")
 			}
+
 			task.Motivation = &motivation
 		}
 	}
@@ -127,11 +143,13 @@ func (h *Handlers) HandleCreateTask(ctx context.Context, request mcp.CallToolReq
 		if !ok {
 			return reportMCPError("'status' must be a string")
 		}
+
 		if status != "" {
 			validStatus := map[string]bool{"later": true, "next": true, "started": true, "waiting": true, "completed": true}
 			if !validStatus[status] {
 				return reportMCPError("'status' must be one of 'later', 'next', 'started', 'waiting', or 'completed'")
 			}
+
 			task.Status = &status
 		}
 	}
@@ -141,10 +159,12 @@ func (h *Handlers) HandleCreateTask(ctx context.Context, request mcp.CallToolReq
 		if !ok {
 			return reportMCPError("Invalid type for 'estimate' argument: expected number.")
 		}
+
 		estimate := int(estimateVal)
 		if estimate < 0 || estimate > 720 {
 			return reportMCPError("'estimate' must be between 0 and 720 minutes")
 		}
+
 		task.Estimate = &estimate
 	}
 
@@ -153,11 +173,13 @@ func (h *Handlers) HandleCreateTask(ctx context.Context, request mcp.CallToolReq
 		if !ok {
 			return reportMCPError("Invalid type for scheduled_on argument: expected string.")
 		}
+
 		if scheduledOnStr != "" {
 			date, err := lunatask.ParseDate(scheduledOnStr)
 			if err != nil {
 				return reportMCPError(fmt.Sprintf("Invalid format for scheduled_on: '%s'. Must be YYYY-MM-DD.", scheduledOnStr))
 			}
+
 			task.ScheduledOn = &date
 		}
 	}
@@ -171,6 +193,7 @@ func (h *Handlers) HandleCreateTask(ctx context.Context, request mcp.CallToolReq
 	}
 
 	client := lunatask.NewClient(h.config.AccessToken)
+
 	response, err := client.CreateTask(ctx, &task)
 	if err != nil {
 		return reportMCPError(fmt.Sprintf("%v", err))
@@ -191,7 +214,7 @@ func (h *Handlers) HandleCreateTask(ctx context.Context, request mcp.CallToolReq
 		Content: []mcp.Content{
 			mcp.TextContent{
 				Type: "text",
-				Text: fmt.Sprintf("Task created successfully with ID: %s", response.ID),
+				Text: "Task created successfully with ID: " + response.ID,
 			},
 		},
 	}, nil
@@ -213,6 +236,7 @@ func (h *Handlers) HandleUpdateTask(ctx context.Context, request mcp.CallToolReq
 	updatePayload := lunatask.UpdateTaskRequest{}
 
 	var specifiedAreaProvider AreaProvider
+
 	areaIDProvided := false
 
 	if areaIDArg, exists := arguments["area_id"]; exists {
@@ -220,19 +244,23 @@ func (h *Handlers) HandleUpdateTask(ctx context.Context, request mcp.CallToolReq
 		if !ok && areaIDArg != nil {
 			return reportMCPError("Invalid type for area_id argument: expected string.")
 		}
+
 		if ok && areaIDStr != "" {
 			updatePayload.AreaID = &areaIDStr
 			areaIDProvided = true
 			found := false
+
 			for _, ap := range h.config.Areas {
 				if ap.GetID() == areaIDStr {
 					specifiedAreaProvider = ap
 					found = true
+
 					break
 				}
 			}
+
 			if !found {
-				return reportMCPError(fmt.Sprintf("Area not found for given area_id: %s", areaIDStr))
+				return reportMCPError("Area not found for given area_id: " + areaIDStr)
 			}
 		}
 	}
@@ -242,16 +270,21 @@ func (h *Handlers) HandleUpdateTask(ctx context.Context, request mcp.CallToolReq
 		if !ok && goalIDArg != nil {
 			return reportMCPError("Invalid type for goal_id argument: expected string.")
 		}
+
 		if ok && goalIDStr != "" {
 			updatePayload.GoalID = &goalIDStr
+
 			if specifiedAreaProvider != nil {
 				foundGoal := false
+
 				for _, goal := range specifiedAreaProvider.GetGoals() {
 					if goal.GetID() == goalIDStr {
 						foundGoal = true
+
 						break
 					}
 				}
+
 				if !foundGoal {
 					return reportMCPError(fmt.Sprintf("Goal not found in specified area '%s' for given goal_id: %s", specifiedAreaProvider.GetName(), goalIDStr))
 				}
@@ -266,6 +299,7 @@ func (h *Handlers) HandleUpdateTask(ctx context.Context, request mcp.CallToolReq
 		if len(nameStr) > 100 {
 			return reportMCPError("'name' must be 100 characters or fewer")
 		}
+
 		updatePayload.Name = &nameStr
 	} else {
 		return reportMCPError("Invalid type for name argument: expected string.")
@@ -276,6 +310,7 @@ func (h *Handlers) HandleUpdateTask(ctx context.Context, request mcp.CallToolReq
 		if !ok && noteArg != nil {
 			return reportMCPError("Invalid type for note argument: expected string.")
 		}
+
 		if ok {
 			updatePayload.Note = &noteStr
 		}
@@ -286,10 +321,12 @@ func (h *Handlers) HandleUpdateTask(ctx context.Context, request mcp.CallToolReq
 		if !ok {
 			return reportMCPError("Invalid type for estimate argument: expected number.")
 		}
+
 		estimate := int(estimateVal)
 		if estimate < 0 || estimate > 720 {
 			return reportMCPError("'estimate' must be between 0 and 720 minutes")
 		}
+
 		updatePayload.Estimate = &estimate
 	}
 
@@ -298,6 +335,7 @@ func (h *Handlers) HandleUpdateTask(ctx context.Context, request mcp.CallToolReq
 		if !ok {
 			return reportMCPError("Invalid type for 'priority' argument: expected string.")
 		}
+
 		priorityMap := map[string]int{
 			"lowest":  -2,
 			"low":     -1,
@@ -305,10 +343,12 @@ func (h *Handlers) HandleUpdateTask(ctx context.Context, request mcp.CallToolReq
 			"high":    1,
 			"highest": 2,
 		}
+
 		translatedPriority, isValid := priorityMap[strings.ToLower(priorityStr)]
 		if !isValid {
 			return reportMCPError(fmt.Sprintf("Invalid 'priority' value: '%s'. Must be one of 'lowest', 'low', 'neutral', 'high', 'highest'.", priorityStr))
 		}
+
 		updatePayload.Priority = &translatedPriority
 	}
 
@@ -317,6 +357,7 @@ func (h *Handlers) HandleUpdateTask(ctx context.Context, request mcp.CallToolReq
 		if !ok {
 			return reportMCPError("Invalid type for 'eisenhower' argument: expected string.")
 		}
+
 		eisenhowerMap := map[string]int{
 			"uncategorised":                0,
 			"both urgent and important":    1,
@@ -324,10 +365,12 @@ func (h *Handlers) HandleUpdateTask(ctx context.Context, request mcp.CallToolReq
 			"important, but not urgent":    3,
 			"neither urgent nor important": 4,
 		}
+
 		translatedEisenhower, isValid := eisenhowerMap[strings.ToLower(eisenhowerStr)]
 		if !isValid {
 			return reportMCPError(fmt.Sprintf("Invalid 'eisenhower' value: '%s'. Must be one of 'uncategorised', 'both urgent and important', 'urgent, but not important', 'important, but not urgent', 'neither urgent nor important'.", eisenhowerStr))
 		}
+
 		updatePayload.Eisenhower = &translatedEisenhower
 	}
 
@@ -336,6 +379,7 @@ func (h *Handlers) HandleUpdateTask(ctx context.Context, request mcp.CallToolReq
 		if !ok && motivationArg != nil {
 			return reportMCPError("Invalid type for motivation argument: expected string.")
 		}
+
 		if ok {
 			if motivationStr != "" {
 				validMotivations := map[string]bool{"must": true, "should": true, "want": true}
@@ -343,6 +387,7 @@ func (h *Handlers) HandleUpdateTask(ctx context.Context, request mcp.CallToolReq
 					return reportMCPError("'motivation' must be one of 'must', 'should', or 'want', or empty to clear.")
 				}
 			}
+
 			updatePayload.Motivation = &motivationStr
 		}
 	}
@@ -352,6 +397,7 @@ func (h *Handlers) HandleUpdateTask(ctx context.Context, request mcp.CallToolReq
 		if !ok && statusArg != nil {
 			return reportMCPError("Invalid type for status argument: expected string.")
 		}
+
 		if ok {
 			if statusStr != "" {
 				validStatus := map[string]bool{"later": true, "next": true, "started": true, "waiting": true, "completed": true}
@@ -359,6 +405,7 @@ func (h *Handlers) HandleUpdateTask(ctx context.Context, request mcp.CallToolReq
 					return reportMCPError("'status' must be one of 'later', 'next', 'started', 'waiting', 'completed', or empty.")
 				}
 			}
+
 			updatePayload.Status = &statusStr
 		}
 	}
@@ -368,16 +415,19 @@ func (h *Handlers) HandleUpdateTask(ctx context.Context, request mcp.CallToolReq
 		if !ok && scheduledOnArg != nil {
 			return reportMCPError("Invalid type for scheduled_on argument: expected string.")
 		}
+
 		if ok && scheduledOnStr != "" {
 			date, err := lunatask.ParseDate(scheduledOnStr)
 			if err != nil {
 				return reportMCPError(fmt.Sprintf("Invalid format for scheduled_on: '%s'. Must be YYYY-MM-DD.", scheduledOnStr))
 			}
+
 			updatePayload.ScheduledOn = &date
 		}
 	}
 
 	client := lunatask.NewClient(h.config.AccessToken)
+
 	response, err := client.UpdateTask(ctx, taskID, &updatePayload)
 	if err != nil {
 		return reportMCPError(fmt.Sprintf("Failed to update task: %v", err))
@@ -387,7 +437,7 @@ func (h *Handlers) HandleUpdateTask(ctx context.Context, request mcp.CallToolReq
 		Content: []mcp.Content{
 			mcp.TextContent{
 				Type: "text",
-				Text: fmt.Sprintf("Task updated successfully. ID: %s", response.ID),
+				Text: "Task updated successfully. ID: " + response.ID,
 			},
 		},
 	}, nil
@@ -401,6 +451,7 @@ func (h *Handlers) HandleDeleteTask(ctx context.Context, request mcp.CallToolReq
 	}
 
 	client := lunatask.NewClient(h.config.AccessToken)
+
 	_, err := client.DeleteTask(ctx, taskID)
 	if err != nil {
 		return reportMCPError(fmt.Sprintf("Failed to delete task: %v", err))

tools/tools.go 🔗

@@ -6,6 +6,7 @@ package tools
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"strings"
 	"time"
@@ -59,15 +60,17 @@ func reportMCPError(msg string) (*mcp.CallToolResult, error) {
 	}, nil
 }
 
-// LoadLocation loads a timezone location string, returning a *time.Location or error
+// LoadLocation loads a timezone location string, returning a *time.Location or error.
 func LoadLocation(timezone string) (*time.Location, error) {
 	if timezone == "" {
-		return nil, fmt.Errorf("timezone is not configured; please set the 'timezone' value in your config file (e.g. 'UTC' or 'America/New_York')")
+		return nil, errors.New("timezone is not configured; please set the 'timezone' value in your config file (e.g. 'UTC' or 'America/New_York')")
 	}
+
 	loc, err := time.LoadLocation(timezone)
 	if err != nil {
-		return nil, fmt.Errorf("could not load timezone '%s': %v", timezone, err)
+		return nil, fmt.Errorf("could not load timezone '%s': %w", timezone, err)
 	}
+
 	return loc, nil
 }
 
@@ -77,14 +80,17 @@ func (h *Handlers) HandleGetTimestamp(ctx context.Context, request mcp.CallToolR
 	if !ok || natLangDate == "" {
 		return reportMCPError("Missing or invalid required argument: natural_language_date")
 	}
+
 	loc, err := LoadLocation(h.config.Timezone)
 	if err != nil {
 		return reportMCPError(err.Error())
 	}
+
 	parsedTime, err := anytime.Parse(natLangDate, time.Now().In(loc))
 	if err != nil {
 		return reportMCPError(fmt.Sprintf("Could not parse natural language date: %v", err))
 	}
+
 	return &mcp.CallToolResult{
 		Content: []mcp.Content{
 			mcp.TextContent{
@@ -100,10 +106,12 @@ func (h *Handlers) HandleListAreasAndGoals(ctx context.Context, request mcp.Call
 	var b strings.Builder
 	for _, area := range h.config.Areas {
 		fmt.Fprintf(&b, "- %s: %s\n", area.GetName(), area.GetID())
+
 		for _, goal := range area.GetGoals() {
 			fmt.Fprintf(&b, "  - %s: %s\n", goal.GetName(), goal.GetID())
 		}
 	}
+
 	return &mcp.CallToolResult{
 		Content: []mcp.Content{
 			mcp.TextContent{