diff --git a/pkg/tools/execute/server.go b/pkg/tools/execute/server.go index bf66994..19b6f96 100644 --- a/pkg/tools/execute/server.go +++ b/pkg/tools/execute/server.go @@ -273,7 +273,7 @@ func (e *Server) SetToolRegistry(r *Registry, sessionID string) { } // callPromotedTool executes a tool promoted via the registry by running the -// script file directly as an executable. +// script file directly inside the sandbox. func (e *Server) callPromotedTool(ctx context.Context, tool string, args json.RawMessage) (json.RawMessage, error) { // Resolve script path. if strings.Contains(tool, "/") || strings.Contains(tool, "..") { @@ -281,7 +281,7 @@ func (e *Server) callPromotedTool(ctx context.Context, tool string, args json.Ra } path := filepath.Join(ToolsPath(), tool) - // Parse positional args. + // Parse positional args into a shell command string. var positional []string var argMap map[string]interface{} if err := json.Unmarshal(args, &argMap); err == nil { @@ -294,29 +294,25 @@ func (e *Server) callPromotedTool(ctx context.Context, tool string, args json.Ra } } - var cancel context.CancelFunc - ctx, cancel = context.WithTimeout(ctx, 30*time.Second) - defer cancel() - - // Execute the script directly — shebang handles the interpreter. - e.wdMu.RLock() - workDir := e.cwd - e.wdMu.RUnlock() - if workDir == "" { - workDir, _ = os.Getwd() + // Build a shell command that runs the tool script with its args. + // Quote each arg for safe shell passing. + quoted := make([]string, 0, len(positional)+1) + quoted = append(quoted, path) + for _, a := range positional { + quoted = append(quoted, fmt.Sprintf("%q", a)) } - cmd := exec.CommandContext(ctx, path, positional...) - cmd.Dir = workDir + code := strings.Join(quoted, " ") - output, err := cmd.CombinedOutput() + // Execute through the sandbox via executeWithStdin. + result, err := e.executeWithStdin(ctx, code, "bash", 30, "default", false, "") if err != nil { return json.Marshal(map[string]interface{}{ "isError": true, - "content": []map[string]string{{"type": "text", "text": string(output) + ": " + err.Error()}}, + "content": []map[string]string{{"type": "text", "text": result + ": " + err.Error()}}, }) } return json.Marshal(map[string]interface{}{ - "content": []map[string]string{{"type": "text", "text": string(output)}}, + "content": []map[string]string{{"type": "text", "text": result}}, }) }