pyfig 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +76 -178
  2. package/SECURITY.md +16 -5
  3. package/dist/cjs/index.js +482 -1131
  4. package/dist/cjs/index.js.map +6 -16
  5. package/dist/index.d.ts +2 -8
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +1 -5
  8. package/dist/index.js.map +1 -1
  9. package/dist/process.d.ts +6 -12
  10. package/dist/process.d.ts.map +1 -1
  11. package/dist/process.js +35 -54
  12. package/dist/process.js.map +1 -1
  13. package/dist/pyfig.d.ts +31 -0
  14. package/dist/pyfig.d.ts.map +1 -0
  15. package/dist/pyfig.js +275 -0
  16. package/dist/pyfig.js.map +1 -0
  17. package/dist/uv.d.ts +3 -0
  18. package/dist/uv.d.ts.map +1 -0
  19. package/dist/uv.js +423 -0
  20. package/dist/uv.js.map +1 -0
  21. package/package.json +6 -12
  22. package/dist/cjs/sync-resolver.js +0 -1342
  23. package/dist/cjs/sync-resolver.js.map +0 -20
  24. package/dist/cli.d.ts +0 -3
  25. package/dist/cli.d.ts.map +0 -1
  26. package/dist/cli.js +0 -57
  27. package/dist/cli.js.map +0 -1
  28. package/dist/client.d.ts +0 -15
  29. package/dist/client.d.ts.map +0 -1
  30. package/dist/client.js +0 -35
  31. package/dist/client.js.map +0 -1
  32. package/dist/config.d.ts +0 -69
  33. package/dist/config.d.ts.map +0 -1
  34. package/dist/config.js +0 -159
  35. package/dist/config.js.map +0 -1
  36. package/dist/package-target.d.ts +0 -8
  37. package/dist/package-target.d.ts.map +0 -1
  38. package/dist/package-target.js +0 -81
  39. package/dist/package-target.js.map +0 -1
  40. package/dist/pep440.d.ts +0 -12
  41. package/dist/pep440.d.ts.map +0 -1
  42. package/dist/pep440.js +0 -21
  43. package/dist/pep440.js.map +0 -1
  44. package/dist/probes.d.ts +0 -37
  45. package/dist/probes.d.ts.map +0 -1
  46. package/dist/probes.js +0 -145
  47. package/dist/probes.js.map +0 -1
  48. package/dist/project-root.d.ts +0 -3
  49. package/dist/project-root.d.ts.map +0 -1
  50. package/dist/project-root.js +0 -22
  51. package/dist/project-root.js.map +0 -1
  52. package/dist/provision-lock.d.ts +0 -10
  53. package/dist/provision-lock.d.ts.map +0 -1
  54. package/dist/provision-lock.js +0 -24
  55. package/dist/provision-lock.js.map +0 -1
  56. package/dist/provision.d.ts +0 -20
  57. package/dist/provision.d.ts.map +0 -1
  58. package/dist/provision.js +0 -673
  59. package/dist/provision.js.map +0 -1
  60. package/dist/python-venv.d.ts +0 -12
  61. package/dist/python-venv.d.ts.map +0 -1
  62. package/dist/python-venv.js +0 -52
  63. package/dist/python-venv.js.map +0 -1
  64. package/dist/runners.d.ts +0 -14
  65. package/dist/runners.d.ts.map +0 -1
  66. package/dist/runners.js +0 -71
  67. package/dist/runners.js.map +0 -1
  68. package/dist/runtime-files.d.ts +0 -3
  69. package/dist/runtime-files.d.ts.map +0 -1
  70. package/dist/runtime-files.js +0 -12
  71. package/dist/runtime-files.js.map +0 -1
  72. package/dist/sync-resolver.d.ts +0 -2
  73. package/dist/sync-resolver.d.ts.map +0 -1
  74. package/dist/sync-resolver.js +0 -15
  75. package/dist/sync-resolver.js.map +0 -1
  76. package/dist/venv-identity.d.ts +0 -36
  77. package/dist/venv-identity.d.ts.map +0 -1
  78. package/dist/venv-identity.js +0 -80
  79. package/dist/venv-identity.js.map +0 -1
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # pyfig
2
2
 
3
- `pyfig` prepares uv and compatible Python venvs from Bun or Node.js. It prefers a valid uv already on the system and searches system Python with downloads disabled before considering a managed Python download.
4
-
5
- Pyfig never invokes standalone `pip`, discovers Python project metadata, edits caller-owned requirements files, or creates a project-root `.venv`. Dependency-free callers can reuse a compatible active or project-root venv. A caller that passes dependencies or requirements files gets a content-addressed private venv under `<project-root>/node_modules/.pyfig/venvs/`, so independent libraries cannot replace or downgrade each other's environments.
3
+ `pyfig` resolves compatible uv and Python executables from Node.js or Bun and
4
+ exposes one guarded `uv run` spawn method. Its only managed state is a uv tool
5
+ cache; uv retains responsibility for Python, environments, and dependencies.
6
6
 
7
7
  ## Install
8
8
 
@@ -10,206 +10,100 @@ Pyfig never invokes standalone `pip`, discovers Python project metadata, edits c
10
10
  bun add pyfig
11
11
  ```
12
12
 
13
+ Pyfig reuses a compatible uv from `PATH` or its OS cache. When neither exists,
14
+ it installs the greatest official uv release allowed by the requested version.
15
+ Python discovery and managed installation are delegated to
16
+ [`uv python find`](https://docs.astral.sh/uv/reference/cli/#uv-python-find).
17
+
13
18
  ## Use
14
19
 
15
20
  ```ts
16
- import { Python } from 'pyfig';
21
+ import { pyfig } from 'pyfig';
17
22
 
18
- const pyenv = new Python({
19
- dependencies: ['requests>=2.32'],
20
- requirements: ['requirements/runtime.txt'],
21
- requiresPython: '>=3.11,<4',
22
- requiresUv: '>=0.10,<1',
23
+ const python = await pyfig({
24
+ uv: '>=0.10,<1',
25
+ python: '>=3.11,<4',
23
26
  requireEmbedding: true,
24
27
  requireGil: true,
25
28
  });
26
29
 
27
- const environment = await pyenv.prepare();
30
+ console.log(python.uv);
31
+ console.log(python.python);
28
32
 
29
- console.log(environment.uv);
30
- console.log(environment.python);
31
- console.log(environment.managed);
32
- console.log(environment.venvId);
33
-
34
- await pyenv.uv(
35
- ['run', '--', 'python', 'script.py'],
36
- { stdio: 'inherit' },
37
- );
33
+ python.run('python', '--version', { stdio: 'inherit' });
38
34
  ```
39
35
 
40
- `dependencies` accepts the requirement syntax uv supports, including PEP 508 specifiers, Git references, URLs, and local file references. `requirements` accepts explicit requirements-file paths, with relative paths resolved from `projectRoot`. Pyfig validates each value as one line and otherwise passes it to uv without interpreting package or source syntax. It does not discover or read `pyproject.toml`, Python lockfiles, or dependency groups. Configuration is bound by the `Python` constructor, so `prepare()`, `uv()`, and `uvSync()` always target the same venv. Temporary resolution inputs are created outside the repository and removed afterward.
41
-
42
- The same uv-only surface handles direct commands:
36
+ `pyfig()` returns a `PythonContext` containing:
43
37
 
44
- ```ts
45
- import { uvSpawn, uvSpawnSync } from 'pyfig';
38
+ | Field | Meaning |
39
+ | --- | --- |
40
+ | `uv` | Absolute path to the resolved uv executable. |
41
+ | `python` | Absolute path to the resolved Python interpreter. |
42
+ | `run(...args)` | Spawn `uv run` with that Python interpreter. |
46
43
 
47
- await uvSpawn(['pip', 'list'], { stdio: 'inherit' });
44
+ `run()` treats a final object as Node `SpawnOptions`. When no `--` argument is
45
+ present, every string is treated as command argv:
48
46
 
49
- const result = uvSpawnSync(
50
- ['run', '--', 'python', '-c', 'import sys; print(sys.executable)'],
51
- { encoding: 'utf8' },
52
- );
47
+ ```ts
48
+ python.run('python', '--version');
49
+ // uv run --python /resolved/python -- python --version
53
50
  ```
54
51
 
55
- For `uv pip` and `uv run`, Pyfig selects the venv and injects its exact interpreter. Caller-supplied target overrides such as `--python`, `--system`, `--target`, `--prefix`, and `--user` are rejected. Inherited target-changing environment variables are removed. Other uv commands run with Pyfig's cache and system-Python preference but are otherwise unchanged.
56
-
57
- The async spawn helper returns `Promise<ChildProcess>` because uv or environment setup may happen before spawning. The synchronous helper performs setup through `process.execPath`, so a Bun process remains Bun and does not assume a `node` command exists.
58
-
59
- ## Selection policy
60
-
61
- Pyfig uses this order:
62
-
63
- 1. A compatible configured or `PATH` uv.
64
- 2. Pyfig's cached, checksum-verified uv.
65
- 3. For callers without dependencies or requirements files, a compatible explicitly configured venv, active `VIRTUAL_ENV`, or root `.venv`.
66
- 4. A compatible base interpreter from those venvs, then every installed system Python reported by uv with downloads disabled.
67
- 5. An already-cached uv-managed Python that passes the same checks.
68
- 6. A managed Python download, only when installation policy allows it.
69
- 7. An existing hashed venv for the exact interpreter and resolved dependencies, or a new venv below `node_modules/.pyfig/venvs`.
70
-
71
- An explicit `python` option is strict: an unavailable or incompatible interpreter is an error. Without runtime requirements, an explicitly configured compatible venv can be reused. With dependencies or requirements files, its base interpreter is used for a private venv. Incompatible external venvs are always preserved. Only an incomplete or damaged Pyfig-managed venv may be rebuilt.
72
-
73
- ![Pyfig prefers existing uv, compatible venvs, and system Python before managed downloads](docs/diagrams/python-selection.png)
74
-
75
- [Mermaid source](docs/diagrams/python-selection.mmd)
76
-
77
- Native consumers can set `requireEmbedding: true` to require CPython, `Python.h`, a linkable embedding library, and architecture/pointer-width compatibility with the JavaScript runtime. Set `requireGil: true` when the native addon requires the standard GIL-enabled ABI. These checks apply to system, existing-venv, cached, and downloaded interpreters alike.
78
-
79
- ## Runtime dependency resolution
52
+ When `--` is present, strings before it are passed to uv and strings after it
53
+ are command argv:
80
54
 
81
55
  ```ts
82
- const pyenv = new Python({
83
- dependencies: ['orjson>=3.10', 'httpx[http2]'],
84
- requirements: ['requirements/runtime.txt'],
56
+ python.run('--no-project', '--with', 'httpx', '--', 'python', 'script.py', {
57
+ cwd: '/workspace',
58
+ stdio: 'inherit',
85
59
  });
86
-
87
- await pyenv.prepare();
88
- ```
89
-
90
- Resolution follows the equivalent of:
91
-
92
- ```sh
93
- uv pip compile /project/requirements/runtime.txt \
94
- /temporary/runtime-dependencies.txt \
95
- --python /selected/base/python \
96
- --no-header --no-annotate --generate-hashes \
97
- --output-file /temporary/resolved-dependencies.txt
98
-
99
- uv venv --python /selected/base/python \
100
- node_modules/.pyfig/venvs/cpython-3.12.7-0123456789abcdef0123
101
-
102
- uv pip install \
103
- --python /hashed/venv/python \
104
- -r /temporary/resolved-dependencies.txt
105
60
  ```
106
61
 
107
- The venv identity includes the exact base interpreter, platform, architecture, GIL/ABI properties, and SHA-256 of uv's complete compiled resolution. This includes every artifact hash emitted by `uv pip compile --generate-hashes`. uv also resolves Git references to commit hashes. Pyfig does not duplicate uv's dependency parser or invent hashes for source types uv cannot hash. Equivalent resolutions can share one venv; a changed artifact hash, Git commit, or other resolved output creates another. The metadata file inside each venv is written last and acts as its publication marker.
108
-
109
- Only the explicit `dependencies` values and `requirements` files participate in resolution. Known Python project metadata and lockfile paths are rejected as requirements inputs. Pyfig does not use `uv add` or `uv pip sync`, so it neither edits project metadata nor removes packages from an externally owned venv.
110
-
111
- Raw `pyenv.uv(['pip', ...])` remains an intentional low-level escape hatch. It can mutate the selected venv after publication and bypass the content-addressing guarantee. Use constructor-level `dependencies` or `requirements` when isolation and repeatability matter.
112
-
113
- Separate venvs work for subprocesses and isolated workers. Native libraries that initialize CPython in the same JavaScript process must use one combined compatible dependency set or move each interpreter into a separate worker process; two venv directories cannot provide two independent process-global CPython runtimes.
114
-
115
- ![Runtime dependencies are resolved in temporary files before installation](docs/diagrams/runtime-dependencies.png)
116
-
117
- [Mermaid source](docs/diagrams/runtime-dependencies.mmd)
118
-
119
- ## Project root
120
-
121
- Pyfig does not interpret `package.json`, workspace metadata, `pyproject.toml`, or lockfiles. The root only locates private venv storage and resolves relative requirements-file paths. Root precedence is:
62
+ Pyfig inserts `--python <python>` immediately before the separator. Caller
63
+ supplied `--python <value>` and `--python=<value>` arguments are rejected before
64
+ `--`; Python is selected only by `pyfig()`. A `--python` appearing after
65
+ `--` belongs to the command and is left untouched.
122
66
 
123
- 1. `projectRoot`
124
- 2. `PYFIG_PROJECT_ROOT`
125
- 3. nearest Git worktree marker above `INIT_CWD`, when set, otherwise the current directory
126
- 4. that starting directory when no Git marker exists
67
+ `pyfig()` accepts:
127
68
 
128
- Set `projectRoot` explicitly in reusable libraries and unusual workspace layouts.
129
-
130
- ## Public API
131
-
132
- | Export | Responsibility |
133
- | --- | --- |
134
- | `new Python(options)` | Bind one immutable venv configuration and memoize its preparation. |
135
- | `pyenv.prepare()` | Resolve and prepare that configuration's exact venv. |
136
- | `pyenv.pythonInfo()` | Return the selected interpreter and embedding metadata. |
137
- | `pyenv.uvInfo()` | Return the selected uv executable and version. |
138
- | `pyenv.uv()` / `pyenv.uvSync()` | Spawn uv and pin pip/run commands to the same venv. |
139
- | `ensurePython(options?)` | Standalone Python preparation API using the same options. |
140
- | `ensureUv(options?)` | Prefer existing uv, otherwise bootstrap verified uv when allowed. |
141
- | `uvSpawn()` / `uvSpawnSync()` | Standalone uv spawn API. |
142
- | `resolveProjectRoot(start?)` | Resolve the nearest Git root without reading manifests. |
143
-
144
- The package exposes matching ESM and CommonJS entry points. Probe, download, lock, and command-policy internals are not exported.
145
-
146
- ## Configuration
147
-
148
- Precedence is API or CLI option, environment variable, then default.
149
-
150
- `requiresPython` and `requiresUv` use PEP 440 specifiers. Comma-separated clauses, compatible releases (`~=`), exclusions (`!=`), wildcard equality, arbitrary equality (`===`), and pre-release versions are supported. For example: `requiresPython: '>=3.10,!=3.12.*,<4'` and `requiresUv: '==0.13.*'`. Pyfig reuses a compatible installed or cached uv first. When installation is necessary, it resolves the greatest published uv release satisfying `requiresUv` and containing the required platform assets.
151
-
152
- When embedding files are available, `PythonInfo.embedding.stableAbiLibraryPath` identifies the platform's Python 3 Stable ABI import library when the installation provides one. Consumers can use it to build a single Limited API binary for multiple CPython 3 minor versions while retaining `libraryPath` for version-specific embedding.
153
-
154
- | API option | Environment variable | Default |
69
+ | Option | Default | Meaning |
155
70
  | --- | --- | --- |
156
- | `dependencies` | — | `[]` |
157
- | `requirements` | — | `[]` |
158
- | `python` | `PYFIG_PYTHON` | uv discovery |
159
- | `requiresPython` | `PYFIG_REQUIRES_PYTHON` | `>=3.10,<4` |
160
- | `managedPython` | `PYFIG_MANAGED_PYTHON` | `3.12` |
161
- | `requiresUv` | `PYFIG_REQUIRES_UV` | `>=0.10,<1` |
162
- | `cacheDir` | `PYFIG_HOME` | OS cache directory |
163
- | `projectRoot` | `PYFIG_PROJECT_ROOT` | `INIT_CWD`, Git root, or current directory |
164
- | `requireEmbedding` | `PYFIG_REQUIRE_EMBEDDING` | `false` |
165
- | `requireGil` | `PYFIG_REQUIRE_GIL` | `false` |
166
- | `autoInstall` | `PYFIG_AUTO_INSTALL` | `true` |
167
- | `installPython` | `PYFIG_INSTALL_PYTHON` | `autoInstall` |
168
- | `installUv` | `PYFIG_INSTALL_UV` | `autoInstall` |
169
- | `createVirtualEnvironment` | `PYFIG_CREATE_VIRTUAL_ENVIRONMENT` | `autoInstall` |
170
- | `probeTimeoutMs` | `PYFIG_PROBE_TIMEOUT_MS` | `10000` |
171
- | `installTimeoutMs` | `PYFIG_INSTALL_TIMEOUT_MS` | `600000` |
172
- | `downloadTimeoutMs` | `PYFIG_DOWNLOAD_TIMEOUT_MS` | `300000` |
173
- | `coordinationTimeoutMs` | `PYFIG_COORDINATION_TIMEOUT_MS` | install + download + 60 seconds |
174
-
175
- Set `PYFIG_UV` to choose an explicit uv executable. Set `PYFIG_AUTO_INSTALL=0` or use the CLI's `--check` flag on hosts where downloads and environment creation are prohibited.
176
-
177
- ## CLI
178
-
179
- ```sh
180
- bunx --bun pyfig
181
- bunx --bun pyfig --check
182
- bunx --bun pyfig --requires-python '>=3.12,<3.14'
183
- bunx --bun pyfig --requires-uv '>=0.12,<1'
184
- bunx --bun pyfig --dependency 'requests>=2.32' --requirement requirements/runtime.txt
185
- bunx --bun pyfig --require-embedding --require-gil
186
- bunx --bun pyfig --project-root /path/to/repository
187
- bunx --bun pyfig --json
188
- ```
189
-
190
- `bunx --bun` runs the CLI with Bun and does not require a separate Node.js executable.
191
-
192
- ## Concurrency and installation safety
71
+ | `uv` | `>=0.10,<1` | uv executable or PEP 440 version constraint. |
72
+ | `python` | system, then managed | Python executable or PEP 440 version constraint. |
73
+ | `requireEmbedding` | `false` | Require CPython headers, a linkable library, and matching architecture. |
74
+ | `requireGil` | `false` | Reject free-threaded Python builds. |
75
+ | `cwd` | `process.cwd()` | Directory used for uv configuration and project discovery. |
76
+ | `env` | `process.env` | Environment used to locate executables and invoke child processes. |
77
+
78
+ For both `uv` and `python`, Pyfig first checks whether the value resolves to an
79
+ executable. An executable wins over version parsing. An explicit uv executable
80
+ is trusted without a version check or setup. An explicit Python executable skips
81
+ version selection and installation, but it must still be a working Python and
82
+ satisfy requested embedding, architecture, and GIL capabilities. A value that
83
+ is not executable must be a valid PEP 440 specifier.
84
+
85
+ For a Python version specifier, Pyfig first asks uv for a matching system
86
+ interpreter. If it is absent or fails the requested capabilities, Pyfig asks uv
87
+ for a managed interpreter. For a uv version specifier, Pyfig checks `PATH`, then
88
+ its cache, then downloads a matching checksum-verified release. Cached
89
+ executables are used without a metadata or network request. Release metadata is
90
+ cached for 24 hours and refreshed under Loqkit's layered check-lock-check flow.
91
+ The cache lives below `%LOCALAPPDATA%\pyfig` on Windows,
92
+ `~/Library/Caches/pyfig` on macOS, and `${XDG_CACHE_HOME:-~/.cache}/pyfig` on
93
+ Linux.
94
+
95
+ Executable paths can be used directly:
193
96
 
194
- Pyfig resolves a compatible uv release from Astral's GitHub releases, downloads that exact archive over HTTPS, verifies its adjacent SHA-256 checksum, validates the staged executable version, and atomically publishes it in Pyfig's cache. A compatible cached executable is probed locally without a network request. Release metadata is cached on disk for 24 hours; stale metadata is refreshed under a Loqkit lock and remains available as a fallback when GitHub's API is temporarily unavailable. Set `GITHUB_TOKEN` or `GH_TOKEN` to authenticate release discovery on CI and other rate-limited hosts. Pyfig does not execute installer scripts or modify shell profiles.
195
-
196
- Provisioning mutations use Loqkit's layered in-memory, worker, native-file-lock-when-available, and portable-file coordination with capability checks before and after acquisition. Compatible managed uv executables are cached by resolved version; Loqkit coordinates both the `requiresUv` policy lookup and exact release publication. Each hashed venv has its own provisioning key. Creation, installation, and validation finish before the venv metadata marker is published. Preparation is memoized within one `pyenv`; separate processes converge through the same resolved identity and Loqkit lock.
197
-
198
- ## Platform support
199
-
200
- Pyfig bootstraps uv on x64 and arm64 Windows, macOS, and Linux. Linux uses Astral's static musl artifact, which also runs on glibc. Node.js 22.11+ on the 22.x line, Node.js 24.10 through 26.x, and Bun 1.2+ are supported. Other JavaScript runtimes may work when they provide compatible Node built-ins and process semantics.
201
-
202
- ## Publishing
203
-
204
- Pyfig publishes from a `v<package-version>` Git tag through `.github/workflows/publish.yml`. The trusted-publishing workflow validates the tag, rejects an existing registry version, builds and audits one archive, and publishes that archive with provenance.
205
-
206
- From a clean, synchronized `main` branch:
207
-
208
- ```sh
209
- bun run release
97
+ ```ts
98
+ const python = await pyfig({
99
+ uv: '/opt/bin/uv',
100
+ python: '/opt/python/bin/python3',
101
+ requireEmbedding: true,
102
+ });
210
103
  ```
211
104
 
212
- The local gate derives the next version from remote GitHub tags, verifies locally, audits the package, commits, tags, and atomically pushes. Use `bun run release -- minor`, `bun run release -- major`, or `bun run release -- --dry-run` as needed. Tag publishing intentionally does not repeat the local test suite.
105
+ The runtime package exports `pyfig` and `PythonContext`. TypeScript also exposes
106
+ `PyfigOptions`. Matching ESM and CommonJS entry points are published.
213
107
 
214
108
  ## Development
215
109
 
@@ -217,7 +111,11 @@ The local gate derives the next version from remote GitHub tags, verifies locall
217
111
  bun install --ignore-scripts
218
112
  bun run verify
219
113
  bun run build
220
- bun pm pack --dry-run
221
114
  ```
222
115
 
223
- MIT licensed.
116
+ ## Publishing
117
+
118
+ From a clean, synchronized `main` branch, `bun run release` verifies locally,
119
+ builds and audits the package, commits the next version, creates its Git tag,
120
+ and pushes both atomically. The tag workflow publishes that exact package to
121
+ npm through trusted publishing.
package/SECURITY.md CHANGED
@@ -1,9 +1,20 @@
1
1
  # Security
2
2
 
3
- Pyfig can download Astral uv release archives and can ask uv to download Python distributions. Automatic installation is enabled by default; set `autoInstall: false`, pass `--check`, or set `PYFIG_AUTO_INSTALL=0` when downloads are not allowed.
3
+ Pyfig spawns only the uv executable resolved from `uv`, found on `PATH`, or
4
+ installed in its OS cache. Setup downloads an official Astral release archive
5
+ and adjacent SHA-256 checksum over HTTPS, verifies the archive before
6
+ publication, and probes the staged executable. It never runs an installer
7
+ script, invokes a shell by default, or modifies shell and project configuration.
4
8
 
5
- Pyfig resolves a uv release allowed by `requiresUv`, then fetches that exact release URL over HTTPS with bounded redirects and timeouts. GitHub release metadata is cached for 24 hours under Loqkit coordination, with validated stale metadata available if refresh fails. Pyfig verifies the adjacent SHA-256 checksum, validates the staged executable's reported version, and atomically publishes it into its cache. It never executes an installer script or modifies shell profiles or the host `PATH`. Proxy variables are honored through a per-request dispatcher without logging proxy credentials.
9
+ Compatible cached uv executables are used without network access. GitHub release
10
+ metadata is cached for 24 hours, with valid stale metadata retained as a network
11
+ fallback. Cache publication and metadata refresh use Loqkit's in-memory,
12
+ worker, native-flock-when-available, and portable file-lock coordination.
6
13
 
7
- Provisioning uses in-process, worker, optional native advisory, and portable filesystem coordination followed by a post-lock capability check. Runtime dependency mutation uses uv's target-environment lock. Pyfig pins uv commands to the selected venv and removes configuration values that could redirect them. It resolves only caller-provided dependency specifiers and requirements files; it does not discover or read Python project metadata. Caller-owned requirements files are read-only.
8
-
9
- Executable paths, project roots, version specifiers, package specifications, indexes, and proxy settings remain trusted configuration. Do not let an untrusted user choose `python`, `PYFIG_UV`, `cacheDir`, package arguments, or related environment variables in a privileged process. A checksum fetched from the same release protects transfer integrity, not a compromised upstream publisher.
14
+ The executable path, working directory, environment, version requests, uv
15
+ arguments, command arguments, and spawn options are trusted caller input. The
16
+ `run()` method can execute arbitrary commands, and callers can explicitly
17
+ enable shell execution through `SpawnOptions`. uv owns Python discovery and
18
+ managed-Python downloads. Supply an explicit uv executable or pre-populate the
19
+ cache when setup downloads are prohibited, and configure uv itself when Python
20
+ downloads must be offline or restricted by organizational policy.