Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ jobs:
test:
name: Test (py${{ matrix.python-version }}, ${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 15
timeout-minutes: 30
strategy:
matrix:
# Temporarily excluding macos-latest due to GitHub Actions runner resource constraints
Expand Down Expand Up @@ -152,7 +152,7 @@ jobs:
test-npx-fallback:
name: Test npx fallback (py${{ matrix.python-version }}, ${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 15
timeout-minutes: 30
strategy:
matrix:
# Test npx fallback (without global install)
Expand Down
55 changes: 30 additions & 25 deletions src/promptfoo/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

_WRAPPER_ENV = "PROMPTFOO_PY_WRAPPER"
_WINDOWS_SHELL_EXTENSIONS = (".bat", ".cmd")
_VERSION_ENV = "PROMPTFOO_VERSION"


def check_node_installed() -> bool:
Expand Down Expand Up @@ -178,33 +179,37 @@ def main() -> NoReturn:

Executes promptfoo using subprocess.run() with minimal configuration.
"""
# Check for Node.js installation
if not check_node_installed():
print_installation_help()
sys.exit(1)

# Build command: try external promptfoo first, fall back to npx
promptfoo_path = None if os.environ.get(_WRAPPER_ENV) else _find_external_promptfoo()
if promptfoo_path:
record_wrapper_used("global")
cmd = [promptfoo_path] + sys.argv[1:]
env = os.environ.copy()
env[_WRAPPER_ENV] = "1"
result = _run_command(cmd, env=env)
else:
npx_path = shutil.which("npx")
if npx_path:
record_wrapper_used("npx")
cmd = [npx_path, "-y", "promptfoo@latest"] + sys.argv[1:]
result = _run_command(cmd)
else:
record_wrapper_used("error")
print("ERROR: Neither promptfoo nor npx is available.", file=sys.stderr)
print("Please install promptfoo: npm install -g promptfoo", file=sys.stderr)
print("Or ensure Node.js is properly installed.", file=sys.stderr)
try:
# Check for Node.js installation
if not check_node_installed():
print_installation_help()
sys.exit(1)

sys.exit(result.returncode)
# Build command: try external promptfoo first, fall back to npx
promptfoo_path = None if os.environ.get(_WRAPPER_ENV) else _find_external_promptfoo()
if promptfoo_path:
record_wrapper_used("global")
cmd = [promptfoo_path] + sys.argv[1:]
env = os.environ.copy()
env[_WRAPPER_ENV] = "1"
result = _run_command(cmd, env=env)
else:
npx_path = shutil.which("npx")
if npx_path:
record_wrapper_used("npx")
version = os.environ.get(_VERSION_ENV, "latest")
cmd = [npx_path, "-y", f"promptfoo@{version}"] + sys.argv[1:]
result = _run_command(cmd)
else:
record_wrapper_used("error")
print("ERROR: Neither promptfoo nor npx is available.", file=sys.stderr)
print("Please install promptfoo: npm install -g promptfoo", file=sys.stderr)
print("Or ensure Node.js is properly installed.", file=sys.stderr)
sys.exit(1)

sys.exit(result.returncode)
except KeyboardInterrupt:
sys.exit(130)


if __name__ == "__main__":
Expand Down
12 changes: 6 additions & 6 deletions src/promptfoo/instructions.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ def _get_wsl_instructions() -> list[str]:
"Recommended approach:",
" 1. Use your Linux distribution's package manager (see below)",
" 2. Or use nvm for version management:",
" curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash",
" curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash",
" source ~/.bashrc",
" nvm install 20",
"",
Expand Down Expand Up @@ -255,7 +255,7 @@ def _get_debian_instructions(env: Environment) -> list[str]:
lines.extend(
[
"You don't have sudo access. Use nvm (Node Version Manager):",
" curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash",
" curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash",
" source ~/.bashrc",
" nvm install 20",
]
Expand Down Expand Up @@ -290,7 +290,7 @@ def _get_rhel_instructions(env: Environment) -> list[str]:
lines.extend(
[
"Use nvm (Node Version Manager) - no sudo needed:",
" curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash",
" curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash",
" source ~/.bashrc",
" nvm install 20",
]
Expand All @@ -315,7 +315,7 @@ def _get_rhel_instructions(env: Environment) -> list[str]:
lines.extend(
[
"Use nvm (Node Version Manager) - no sudo needed:",
" curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash",
" curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash",
" source ~/.bashrc",
" nvm install 20",
]
Expand Down Expand Up @@ -362,7 +362,7 @@ def _get_generic_linux_instructions() -> list[str]:
"Use your package manager to install Node.js, or use nvm:",
"",
"Option 1 - nvm (Node Version Manager, works on any Linux):",
" curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash",
" curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash",
" source ~/.bashrc",
" nvm install 20",
"",
Expand All @@ -379,7 +379,7 @@ def _get_macos_instructions() -> list[str]:
" brew install node",
"",
"Option 2 - nvm (Node Version Manager, for version management):",
" curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash",
" curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash",
" source ~/.zshrc # or ~/.bashrc",
" nvm install 20",
"",
Expand Down