diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f58eeaf..be532a4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -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 @@ -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) diff --git a/src/promptfoo/cli.py b/src/promptfoo/cli.py index 7bb0a67..2d35896 100644 --- a/src/promptfoo/cli.py +++ b/src/promptfoo/cli.py @@ -15,6 +15,7 @@ _WRAPPER_ENV = "PROMPTFOO_PY_WRAPPER" _WINDOWS_SHELL_EXTENSIONS = (".bat", ".cmd") +_VERSION_ENV = "PROMPTFOO_VERSION" def check_node_installed() -> bool: @@ -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__": diff --git a/src/promptfoo/instructions.py b/src/promptfoo/instructions.py index 0133f05..dfe1994 100644 --- a/src/promptfoo/instructions.py +++ b/src/promptfoo/instructions.py @@ -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", "", @@ -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", ] @@ -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", ] @@ -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", ] @@ -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", "", @@ -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", "",