diff --git a/cmd/security/cmd_jobs.go b/cmd/security/cmd_jobs.go index cade7ef..607c506 100644 --- a/cmd/security/cmd_jobs.go +++ b/cmd/security/cmd_jobs.go @@ -1,13 +1,14 @@ package security import ( + "errors" "fmt" "os/exec" "strings" "time" - "forge.lthn.ai/core/go-ai/ai" "forge.lthn.ai/core/cli/pkg/cli" + "forge.lthn.ai/core/go-ai/ai" "forge.lthn.ai/core/go/pkg/i18n" ) @@ -68,7 +69,7 @@ func runJobs() error { func createJobForTarget(target string) error { parts := strings.SplitN(target, "/", 2) if len(parts) != 2 { - return fmt.Errorf("invalid target format: use owner/repo") + return errors.New("invalid target format: use owner/repo") } // Gather findings diff --git a/cmd/security/cmd_security.go b/cmd/security/cmd_security.go index f27dede..7463515 100644 --- a/cmd/security/cmd_security.go +++ b/cmd/security/cmd_security.go @@ -146,7 +146,7 @@ func runGHAPI(endpoint string) ([]byte, error) { return []byte("[]"), nil // Return empty array for not found } if strings.Contains(stderr, "403") { - return nil, fmt.Errorf("access denied (check token permissions)") + return nil, errors.New("access denied (check token permissions)") } } return nil, cli.Wrap(err, "run gh api") diff --git a/mcp/ide/bridge.go b/mcp/ide/bridge.go index e0d7cbf..7897568 100644 --- a/mcp/ide/bridge.go +++ b/mcp/ide/bridge.go @@ -3,6 +3,7 @@ package ide import ( "context" "encoding/json" + "errors" "fmt" "log" "net/http" @@ -73,7 +74,7 @@ func (b *Bridge) Send(msg BridgeMessage) error { b.mu.Lock() defer b.mu.Unlock() if b.conn == nil { - return fmt.Errorf("bridge: not connected") + return errors.New("bridge: not connected") } msg.Timestamp = time.Now() data, err := json.Marshal(msg) diff --git a/mcp/ide/tools_build.go b/mcp/ide/tools_build.go index 30344cd..b3e4197 100644 --- a/mcp/ide/tools_build.go +++ b/mcp/ide/tools_build.go @@ -2,7 +2,7 @@ package ide import ( "context" - "fmt" + "errors" "time" "github.com/modelcontextprotocol/go-sdk/mcp" @@ -74,7 +74,7 @@ func (s *Subsystem) registerBuildTools(server *mcp.Server) { // Stub implementation: sends request via bridge, returns "unknown" status. Awaiting Laravel backend. func (s *Subsystem) buildStatus(_ context.Context, _ *mcp.CallToolRequest, input BuildStatusInput) (*mcp.CallToolResult, BuildStatusOutput, error) { if s.bridge == nil { - return nil, BuildStatusOutput{}, fmt.Errorf("bridge not available") + return nil, BuildStatusOutput{}, errors.New("bridge not available") } _ = s.bridge.Send(BridgeMessage{ Type: "build_status", @@ -89,7 +89,7 @@ func (s *Subsystem) buildStatus(_ context.Context, _ *mcp.CallToolRequest, input // Stub implementation: sends request via bridge, returns empty list. Awaiting Laravel backend. func (s *Subsystem) buildList(_ context.Context, _ *mcp.CallToolRequest, input BuildListInput) (*mcp.CallToolResult, BuildListOutput, error) { if s.bridge == nil { - return nil, BuildListOutput{}, fmt.Errorf("bridge not available") + return nil, BuildListOutput{}, errors.New("bridge not available") } _ = s.bridge.Send(BridgeMessage{ Type: "build_list", @@ -102,7 +102,7 @@ func (s *Subsystem) buildList(_ context.Context, _ *mcp.CallToolRequest, input B // Stub implementation: sends request via bridge, returns empty lines. Awaiting Laravel backend. func (s *Subsystem) buildLogs(_ context.Context, _ *mcp.CallToolRequest, input BuildLogsInput) (*mcp.CallToolResult, BuildLogsOutput, error) { if s.bridge == nil { - return nil, BuildLogsOutput{}, fmt.Errorf("bridge not available") + return nil, BuildLogsOutput{}, errors.New("bridge not available") } _ = s.bridge.Send(BridgeMessage{ Type: "build_logs", diff --git a/mcp/ide/tools_chat.go b/mcp/ide/tools_chat.go index 20f35ba..923e01e 100644 --- a/mcp/ide/tools_chat.go +++ b/mcp/ide/tools_chat.go @@ -2,6 +2,7 @@ package ide import ( "context" + "errors" "fmt" "time" @@ -117,7 +118,7 @@ func (s *Subsystem) registerChatTools(server *mcp.Server) { // Stub implementation: delegates to bridge, real response arrives via WebSocket subscription. func (s *Subsystem) chatSend(_ context.Context, _ *mcp.CallToolRequest, input ChatSendInput) (*mcp.CallToolResult, ChatSendOutput, error) { if s.bridge == nil { - return nil, ChatSendOutput{}, fmt.Errorf("bridge not available") + return nil, ChatSendOutput{}, errors.New("bridge not available") } err := s.bridge.Send(BridgeMessage{ Type: "chat_send", @@ -139,7 +140,7 @@ func (s *Subsystem) chatSend(_ context.Context, _ *mcp.CallToolRequest, input Ch // Stub implementation: sends request via bridge, returns empty messages. Real data arrives via WebSocket. func (s *Subsystem) chatHistory(_ context.Context, _ *mcp.CallToolRequest, input ChatHistoryInput) (*mcp.CallToolResult, ChatHistoryOutput, error) { if s.bridge == nil { - return nil, ChatHistoryOutput{}, fmt.Errorf("bridge not available") + return nil, ChatHistoryOutput{}, errors.New("bridge not available") } // Request history via bridge; for now return placeholder indicating the // request was forwarded. Real data arrives via WebSocket subscription. @@ -158,7 +159,7 @@ func (s *Subsystem) chatHistory(_ context.Context, _ *mcp.CallToolRequest, input // Stub implementation: sends request via bridge, returns empty sessions. Awaiting Laravel backend. func (s *Subsystem) sessionList(_ context.Context, _ *mcp.CallToolRequest, _ SessionListInput) (*mcp.CallToolResult, SessionListOutput, error) { if s.bridge == nil { - return nil, SessionListOutput{}, fmt.Errorf("bridge not available") + return nil, SessionListOutput{}, errors.New("bridge not available") } _ = s.bridge.Send(BridgeMessage{Type: "session_list"}) return nil, SessionListOutput{Sessions: []Session{}}, nil @@ -168,7 +169,7 @@ func (s *Subsystem) sessionList(_ context.Context, _ *mcp.CallToolRequest, _ Ses // Stub implementation: sends request via bridge, returns placeholder session. Awaiting Laravel backend. func (s *Subsystem) sessionCreate(_ context.Context, _ *mcp.CallToolRequest, input SessionCreateInput) (*mcp.CallToolResult, SessionCreateOutput, error) { if s.bridge == nil { - return nil, SessionCreateOutput{}, fmt.Errorf("bridge not available") + return nil, SessionCreateOutput{}, errors.New("bridge not available") } _ = s.bridge.Send(BridgeMessage{ Type: "session_create", @@ -187,7 +188,7 @@ func (s *Subsystem) sessionCreate(_ context.Context, _ *mcp.CallToolRequest, inp // Stub implementation: sends request via bridge, returns "unknown" status. Awaiting Laravel backend. func (s *Subsystem) planStatus(_ context.Context, _ *mcp.CallToolRequest, input PlanStatusInput) (*mcp.CallToolResult, PlanStatusOutput, error) { if s.bridge == nil { - return nil, PlanStatusOutput{}, fmt.Errorf("bridge not available") + return nil, PlanStatusOutput{}, errors.New("bridge not available") } _ = s.bridge.Send(BridgeMessage{ Type: "plan_status", diff --git a/mcp/ide/tools_dashboard.go b/mcp/ide/tools_dashboard.go index 787d9a9..575ca0b 100644 --- a/mcp/ide/tools_dashboard.go +++ b/mcp/ide/tools_dashboard.go @@ -2,7 +2,7 @@ package ide import ( "context" - "fmt" + "errors" "time" "github.com/modelcontextprotocol/go-sdk/mcp" @@ -103,7 +103,7 @@ func (s *Subsystem) dashboardOverview(_ context.Context, _ *mcp.CallToolRequest, // Stub implementation: sends request via bridge, returns empty events. Awaiting Laravel backend. func (s *Subsystem) dashboardActivity(_ context.Context, _ *mcp.CallToolRequest, input DashboardActivityInput) (*mcp.CallToolResult, DashboardActivityOutput, error) { if s.bridge == nil { - return nil, DashboardActivityOutput{}, fmt.Errorf("bridge not available") + return nil, DashboardActivityOutput{}, errors.New("bridge not available") } _ = s.bridge.Send(BridgeMessage{ Type: "dashboard_activity", @@ -116,7 +116,7 @@ func (s *Subsystem) dashboardActivity(_ context.Context, _ *mcp.CallToolRequest, // Stub implementation: sends request via bridge, returns zero metrics. Awaiting Laravel backend. func (s *Subsystem) dashboardMetrics(_ context.Context, _ *mcp.CallToolRequest, input DashboardMetricsInput) (*mcp.CallToolResult, DashboardMetricsOutput, error) { if s.bridge == nil { - return nil, DashboardMetricsOutput{}, fmt.Errorf("bridge not available") + return nil, DashboardMetricsOutput{}, errors.New("bridge not available") } period := input.Period if period == "" { diff --git a/mcp/mcp.go b/mcp/mcp.go index aa22a8d..d386627 100644 --- a/mcp/mcp.go +++ b/mcp/mcp.go @@ -6,6 +6,7 @@ package mcp import ( "context" + "errors" "fmt" "iter" "net/http" @@ -471,7 +472,7 @@ func (s *Service) getSupportedLanguages(ctx context.Context, req *mcp.CallToolRe func (s *Service) editDiff(ctx context.Context, req *mcp.CallToolRequest, input EditDiffInput) (*mcp.CallToolResult, EditDiffOutput, error) { if input.OldString == "" { - return nil, EditDiffOutput{}, fmt.Errorf("old_string cannot be empty") + return nil, EditDiffOutput{}, errors.New("old_string cannot be empty") } content, err := s.medium.Read(input.Path) @@ -484,12 +485,12 @@ func (s *Service) editDiff(ctx context.Context, req *mcp.CallToolRequest, input if input.ReplaceAll { count = strings.Count(content, input.OldString) if count == 0 { - return nil, EditDiffOutput{}, fmt.Errorf("old_string not found in file") + return nil, EditDiffOutput{}, errors.New("old_string not found in file") } content = strings.ReplaceAll(content, input.OldString, input.NewString) } else { if !strings.Contains(content, input.OldString) { - return nil, EditDiffOutput{}, fmt.Errorf("old_string not found in file") + return nil, EditDiffOutput{}, errors.New("old_string not found in file") } content = strings.Replace(content, input.OldString, input.NewString, 1) count = 1 diff --git a/mcp/tools_metrics.go b/mcp/tools_metrics.go index 075f70e..fb123b1 100644 --- a/mcp/tools_metrics.go +++ b/mcp/tools_metrics.go @@ -2,6 +2,7 @@ package mcp import ( "context" + "errors" "fmt" "strconv" "strings" @@ -79,7 +80,7 @@ func (s *Service) metricsRecord(ctx context.Context, req *mcp.CallToolRequest, i // Validate input if input.Type == "" { - return nil, MetricsRecordOutput{}, fmt.Errorf("type cannot be empty") + return nil, MetricsRecordOutput{}, errors.New("type cannot be empty") } // Create the event @@ -178,7 +179,7 @@ func convertMetricCounts(data any) []MetricCount { // parseDuration parses a duration string like "7d", "24h", "30m". func parseDuration(s string) (time.Duration, error) { if s == "" { - return 0, fmt.Errorf("duration cannot be empty") + return 0, errors.New("duration cannot be empty") } s = strings.TrimSpace(s) diff --git a/mcp/tools_ml.go b/mcp/tools_ml.go index 7bc4eb6..1be698e 100644 --- a/mcp/tools_ml.go +++ b/mcp/tools_ml.go @@ -2,6 +2,7 @@ package mcp import ( "context" + "errors" "fmt" "strings" @@ -141,7 +142,7 @@ func (m *MLSubsystem) mlGenerate(ctx context.Context, req *mcp.CallToolRequest, m.logger.Info("MCP tool execution", "tool", "ml_generate", "backend", input.Backend, "user", log.Username()) if input.Prompt == "" { - return nil, MLGenerateOutput{}, fmt.Errorf("prompt cannot be empty") + return nil, MLGenerateOutput{}, errors.New("prompt cannot be empty") } opts := ml.GenOpts{ @@ -166,7 +167,7 @@ func (m *MLSubsystem) mlScore(ctx context.Context, req *mcp.CallToolRequest, inp m.logger.Info("MCP tool execution", "tool", "ml_score", "suites", input.Suites, "user", log.Username()) if input.Prompt == "" || input.Response == "" { - return nil, MLScoreOutput{}, fmt.Errorf("prompt and response cannot be empty") + return nil, MLScoreOutput{}, errors.New("prompt and response cannot be empty") } suites := input.Suites @@ -184,7 +185,7 @@ func (m *MLSubsystem) mlScore(ctx context.Context, req *mcp.CallToolRequest, inp case "semantic": judge := m.service.Judge() if judge == nil { - return nil, MLScoreOutput{}, fmt.Errorf("semantic scoring requires a judge backend") + return nil, MLScoreOutput{}, errors.New("semantic scoring requires a judge backend") } s, err := judge.ScoreSemantic(ctx, input.Prompt, input.Response) if err != nil { @@ -192,7 +193,7 @@ func (m *MLSubsystem) mlScore(ctx context.Context, req *mcp.CallToolRequest, inp } output.Semantic = s case "content": - return nil, MLScoreOutput{}, fmt.Errorf("content scoring requires a ContentProbe — use ml_probe instead") + return nil, MLScoreOutput{}, errors.New("content scoring requires a ContentProbe — use ml_probe instead") } } diff --git a/mcp/tools_process.go b/mcp/tools_process.go index d613042..64412f5 100644 --- a/mcp/tools_process.go +++ b/mcp/tools_process.go @@ -2,6 +2,7 @@ package mcp import ( "context" + "errors" "fmt" "time" @@ -144,7 +145,7 @@ func (s *Service) processStart(ctx context.Context, req *mcp.CallToolRequest, in s.logger.Security("MCP tool execution", "tool", "process_start", "command", input.Command, "args", input.Args, "dir", input.Dir, "user", log.Username()) if input.Command == "" { - return nil, ProcessStartOutput{}, fmt.Errorf("command cannot be empty") + return nil, ProcessStartOutput{}, errors.New("command cannot be empty") } opts := process.RunOptions{ @@ -175,7 +176,7 @@ func (s *Service) processStop(ctx context.Context, req *mcp.CallToolRequest, inp s.logger.Security("MCP tool execution", "tool", "process_stop", "id", input.ID, "user", log.Username()) if input.ID == "" { - return nil, ProcessStopOutput{}, fmt.Errorf("id cannot be empty") + return nil, ProcessStopOutput{}, errors.New("id cannot be empty") } proc, err := s.processService.Get(input.ID) @@ -203,7 +204,7 @@ func (s *Service) processKill(ctx context.Context, req *mcp.CallToolRequest, inp s.logger.Security("MCP tool execution", "tool", "process_kill", "id", input.ID, "user", log.Username()) if input.ID == "" { - return nil, ProcessKillOutput{}, fmt.Errorf("id cannot be empty") + return nil, ProcessKillOutput{}, errors.New("id cannot be empty") } if err := s.processService.Kill(input.ID); err != nil { @@ -256,7 +257,7 @@ func (s *Service) processOutput(ctx context.Context, req *mcp.CallToolRequest, i s.logger.Info("MCP tool execution", "tool", "process_output", "id", input.ID, "user", log.Username()) if input.ID == "" { - return nil, ProcessOutputOutput{}, fmt.Errorf("id cannot be empty") + return nil, ProcessOutputOutput{}, errors.New("id cannot be empty") } output, err := s.processService.Output(input.ID) @@ -276,10 +277,10 @@ func (s *Service) processInput(ctx context.Context, req *mcp.CallToolRequest, in s.logger.Security("MCP tool execution", "tool", "process_input", "id", input.ID, "user", log.Username()) if input.ID == "" { - return nil, ProcessInputOutput{}, fmt.Errorf("id cannot be empty") + return nil, ProcessInputOutput{}, errors.New("id cannot be empty") } if input.Input == "" { - return nil, ProcessInputOutput{}, fmt.Errorf("input cannot be empty") + return nil, ProcessInputOutput{}, errors.New("input cannot be empty") } proc, err := s.processService.Get(input.ID) diff --git a/mcp/tools_rag.go b/mcp/tools_rag.go index 200e2b4..a80df59 100644 --- a/mcp/tools_rag.go +++ b/mcp/tools_rag.go @@ -2,10 +2,11 @@ package mcp import ( "context" + "errors" "fmt" - "forge.lthn.ai/core/go/pkg/log" "forge.lthn.ai/core/go-rag" + "forge.lthn.ai/core/go/pkg/log" "github.com/modelcontextprotocol/go-sdk/mcp" ) @@ -107,7 +108,7 @@ func (s *Service) ragQuery(ctx context.Context, req *mcp.CallToolRequest, input // Validate input if input.Question == "" { - return nil, RAGQueryOutput{}, fmt.Errorf("question cannot be empty") + return nil, RAGQueryOutput{}, errors.New("question cannot be empty") } // Call the RAG query function @@ -150,7 +151,7 @@ func (s *Service) ragIngest(ctx context.Context, req *mcp.CallToolRequest, input // Validate input if input.Path == "" { - return nil, RAGIngestOutput{}, fmt.Errorf("path cannot be empty") + return nil, RAGIngestOutput{}, errors.New("path cannot be empty") } // Check if path is a file or directory using the medium diff --git a/mcp/tools_webview.go b/mcp/tools_webview.go index 8aab06b..9e32ddf 100644 --- a/mcp/tools_webview.go +++ b/mcp/tools_webview.go @@ -3,6 +3,7 @@ package mcp import ( "context" "encoding/base64" + "errors" "fmt" "time" @@ -203,7 +204,7 @@ func (s *Service) webviewConnect(ctx context.Context, req *mcp.CallToolRequest, s.logger.Security("MCP tool execution", "tool", "webview_connect", "debug_url", input.DebugURL, "user", log.Username()) if input.DebugURL == "" { - return nil, WebviewConnectOutput{}, fmt.Errorf("debug_url is required") + return nil, WebviewConnectOutput{}, errors.New("debug_url is required") } // Close existing connection if any @@ -265,11 +266,11 @@ func (s *Service) webviewNavigate(ctx context.Context, req *mcp.CallToolRequest, s.logger.Info("MCP tool execution", "tool", "webview_navigate", "url", input.URL, "user", log.Username()) if webviewInstance == nil { - return nil, WebviewNavigateOutput{}, fmt.Errorf("not connected; use webview_connect first") + return nil, WebviewNavigateOutput{}, errors.New("not connected; use webview_connect first") } if input.URL == "" { - return nil, WebviewNavigateOutput{}, fmt.Errorf("url is required") + return nil, WebviewNavigateOutput{}, errors.New("url is required") } if err := webviewInstance.Navigate(input.URL); err != nil { @@ -288,11 +289,11 @@ func (s *Service) webviewClick(ctx context.Context, req *mcp.CallToolRequest, in s.logger.Info("MCP tool execution", "tool", "webview_click", "selector", input.Selector, "user", log.Username()) if webviewInstance == nil { - return nil, WebviewClickOutput{}, fmt.Errorf("not connected; use webview_connect first") + return nil, WebviewClickOutput{}, errors.New("not connected; use webview_connect first") } if input.Selector == "" { - return nil, WebviewClickOutput{}, fmt.Errorf("selector is required") + return nil, WebviewClickOutput{}, errors.New("selector is required") } if err := webviewInstance.Click(input.Selector); err != nil { @@ -308,11 +309,11 @@ func (s *Service) webviewType(ctx context.Context, req *mcp.CallToolRequest, inp s.logger.Info("MCP tool execution", "tool", "webview_type", "selector", input.Selector, "user", log.Username()) if webviewInstance == nil { - return nil, WebviewTypeOutput{}, fmt.Errorf("not connected; use webview_connect first") + return nil, WebviewTypeOutput{}, errors.New("not connected; use webview_connect first") } if input.Selector == "" { - return nil, WebviewTypeOutput{}, fmt.Errorf("selector is required") + return nil, WebviewTypeOutput{}, errors.New("selector is required") } if err := webviewInstance.Type(input.Selector, input.Text); err != nil { @@ -328,11 +329,11 @@ func (s *Service) webviewQuery(ctx context.Context, req *mcp.CallToolRequest, in s.logger.Info("MCP tool execution", "tool", "webview_query", "selector", input.Selector, "all", input.All, "user", log.Username()) if webviewInstance == nil { - return nil, WebviewQueryOutput{}, fmt.Errorf("not connected; use webview_connect first") + return nil, WebviewQueryOutput{}, errors.New("not connected; use webview_connect first") } if input.Selector == "" { - return nil, WebviewQueryOutput{}, fmt.Errorf("selector is required") + return nil, WebviewQueryOutput{}, errors.New("selector is required") } if input.All { @@ -386,7 +387,7 @@ func (s *Service) webviewConsole(ctx context.Context, req *mcp.CallToolRequest, s.logger.Info("MCP tool execution", "tool", "webview_console", "clear", input.Clear, "user", log.Username()) if webviewInstance == nil { - return nil, WebviewConsoleOutput{}, fmt.Errorf("not connected; use webview_connect first") + return nil, WebviewConsoleOutput{}, errors.New("not connected; use webview_connect first") } messages := webviewInstance.GetConsole() @@ -418,11 +419,11 @@ func (s *Service) webviewEval(ctx context.Context, req *mcp.CallToolRequest, inp s.logger.Security("MCP tool execution", "tool", "webview_eval", "user", log.Username()) if webviewInstance == nil { - return nil, WebviewEvalOutput{}, fmt.Errorf("not connected; use webview_connect first") + return nil, WebviewEvalOutput{}, errors.New("not connected; use webview_connect first") } if input.Script == "" { - return nil, WebviewEvalOutput{}, fmt.Errorf("script is required") + return nil, WebviewEvalOutput{}, errors.New("script is required") } result, err := webviewInstance.Evaluate(input.Script) @@ -445,7 +446,7 @@ func (s *Service) webviewScreenshot(ctx context.Context, req *mcp.CallToolReques s.logger.Info("MCP tool execution", "tool", "webview_screenshot", "format", input.Format, "user", log.Username()) if webviewInstance == nil { - return nil, WebviewScreenshotOutput{}, fmt.Errorf("not connected; use webview_connect first") + return nil, WebviewScreenshotOutput{}, errors.New("not connected; use webview_connect first") } format := input.Format @@ -471,11 +472,11 @@ func (s *Service) webviewWait(ctx context.Context, req *mcp.CallToolRequest, inp s.logger.Info("MCP tool execution", "tool", "webview_wait", "selector", input.Selector, "timeout", input.Timeout, "user", log.Username()) if webviewInstance == nil { - return nil, WebviewWaitOutput{}, fmt.Errorf("not connected; use webview_connect first") + return nil, WebviewWaitOutput{}, errors.New("not connected; use webview_connect first") } if input.Selector == "" { - return nil, WebviewWaitOutput{}, fmt.Errorf("selector is required") + return nil, WebviewWaitOutput{}, errors.New("selector is required") } if err := webviewInstance.WaitForSelector(input.Selector); err != nil {