@@ -40,37 +40,55 @@ def main() -> NoReturn:
4040 """
4141 Main entry point for the promptfoo CLI wrapper.
4242
43- Executes `npx promptfoo@latest <args>` and passes through all arguments .
43+ Tries to use globally installed promptfoo first, falls back to npx .
4444 Exits with the same exit code as the underlying promptfoo command.
4545 """
4646 # Check for Node.js installation
4747 if not check_node_installed ():
4848 print_installation_help ()
4949 sys .exit (1 )
5050
51- npx_path = shutil .which ("npx" )
52- if not npx_path :
53- print ("ERROR: npx is not available. Please ensure Node.js is properly installed." , file = sys .stderr )
54- sys .exit (1 )
55-
56- # Build the command: npx promptfoo@latest <args>
57- # Use @latest to always get the most recent version
5851 is_windows = platform .system () == "Windows"
5952
60- # On Windows, we need special handling for .cmd files
53+ # Try to find a globally installed promptfoo first
54+ promptfoo_path = shutil .which ("promptfoo" )
55+
56+ # Build the command
6157 cmd : Union [str , list [str ]]
62- if is_windows :
63- # On Windows, build command as string for shell=True
64- # This properly handles npx.cmd batch file execution
65- import shlex
66-
67- args = ["npx" , "--yes" , "promptfoo@latest" ] + sys .argv [1 :]
68- cmd = " " .join (shlex .quote (arg ) for arg in args )
69- use_shell = True
58+ use_shell : bool
59+
60+ if promptfoo_path :
61+ # Use the globally installed promptfoo
62+ if is_windows :
63+ # On Windows, build command as string for shell=True to handle .cmd files
64+ import shlex
65+
66+ args = ["promptfoo" ] + sys .argv [1 :]
67+ cmd = " " .join (shlex .quote (arg ) for arg in args )
68+ use_shell = True
69+ else :
70+ # On Unix, use list format with shell=False (more secure)
71+ cmd = [promptfoo_path ] + sys .argv [1 :]
72+ use_shell = False
7073 else :
71- # On Unix, use list format with shell=False (more secure)
72- cmd = [npx_path , "--yes" , "promptfoo@latest" ] + sys .argv [1 :]
73- use_shell = False
74+ # Fall back to npx promptfoo@latest
75+ npx_path = shutil .which ("npx" )
76+ if not npx_path :
77+ print ("ERROR: promptfoo is not installed and npx is not available." , file = sys .stderr )
78+ print ("Please install promptfoo globally: npm install -g promptfoo" , file = sys .stderr )
79+ sys .exit (1 )
80+
81+ if is_windows :
82+ # On Windows, build command as string for shell=True to handle npx.cmd
83+ import shlex
84+
85+ args = ["npx" , "--yes" , "promptfoo@latest" ] + sys .argv [1 :]
86+ cmd = " " .join (shlex .quote (arg ) for arg in args )
87+ use_shell = True
88+ else :
89+ # On Unix, use list format with shell=False (more secure)
90+ cmd = [npx_path , "--yes" , "promptfoo@latest" ] + sys .argv [1 :]
91+ use_shell = False
7492
7593 try :
7694 # Execute the command and pass through stdio
0 commit comments