( pythonPath: string )
| 405 | } |
| 406 | |
| 407 | export async function getUvBinaryOrInstall( |
| 408 | pythonPath: string |
| 409 | ): Promise<string> { |
| 410 | const uvBin = await findUvBinary(pythonPath); |
| 411 | if (uvBin) return uvBin; |
| 412 | |
| 413 | // Pip install uv |
| 414 | // Note we're using pip directly instead of pipPath because we want to make sure |
| 415 | // it is installed in the same environment as the Python interpreter |
| 416 | try { |
| 417 | console.log('Installing uv...'); |
| 418 | await execa( |
| 419 | pythonPath, |
| 420 | [ |
| 421 | '-m', |
| 422 | 'pip', |
| 423 | 'install', |
| 424 | '--disable-pip-version-check', |
| 425 | '--no-cache-dir', |
| 426 | '--user', |
| 427 | `uv==${UV_VERSION}`, |
| 428 | ], |
| 429 | { env: { ...process.env, PIP_USER: '1' } } |
| 430 | ); |
| 431 | } catch (err) { |
| 432 | throw new Error( |
| 433 | `Failed to install uv via pip: ${err instanceof Error ? err.message : String(err)}` |
| 434 | ); |
| 435 | } |
| 436 | |
| 437 | const resolvedUvBin = await findUvBinary(pythonPath); |
| 438 | if (!resolvedUvBin) { |
| 439 | throw new Error('Unable to resolve uv binary after pip install'); |
| 440 | } |
| 441 | |
| 442 | console.log(`Installed uv at "${resolvedUvBin}"`); |
| 443 | return resolvedUvBin; |
| 444 | } |
| 445 | |
| 446 | export function filterUnsafeUvPipArgs(args: string[]): string[] { |
| 447 | // `--no-warn-script-location` is not supported/safe with `uv pip install`, |
no test coverage detected