tag:github.com,2008:https://github.com/ArchiveBox/abxpkg/releases Release notes from abxpkg 2026-04-14T23:46:02Z tag:github.com,2008:Repository/802422164/v1.10.5 2026-04-14T23:47:15Z v1.10.5 <h2>Highlights</h2> <ul> <li>Fixed provider cache ownership so dependency cache entries no longer masquerade as installed binaries. This makes <code>update</code> / <code>upgrade</code> pick real owning providers again, e.g. <code>brew</code> can upgrade <code>node</code> even when other providers cache <code>node</code> as an upstream dependency.</li> <li>Added shared <code>BinProvider.depends_on_binaries()</code> and <code>BinProvider.installed_binaries()</code> APIs and switched provider sections in <code>abxpkg version</code> to use them directly.</li> <li>Tightened update verification so normal post-update checks reuse cached installer dependencies when appropriate, while explicit <code>--no-cache</code> still forces a fully fresh path.</li> <li>Cleaned up CLI output: provider binary rows in <code>abxpkg version</code> now use a fixed-width version column, non-debug progress logs no longer inherit misleading deep indentation, and shared subprocess stderr/stdout formatting is more consistent.</li> </ul> <h2>Docs</h2> <ul> <li>Updated the README and generated docs to match current defaults and flag behavior, especially around <code>None</code> handling for <code>postinstall_scripts</code> / <code>min_release_age</code>, managed <code>ABXPKG_LIB_DIR</code> install roots, and the current visible CLI surface.</li> </ul> pirate tag:github.com,2008:Repository/802422164/v1.10.4 2026-04-14T22:53:05Z v1.10.4 <h1>abxpkg v1.10.4</h1> <h2>✨ Highlights</h2> <ul> <li>Added richer CLI inspection commands with <code>abxpkg version</code> and <code>abxpkg list</code>, including per-provider runtime state, installer provenance, dependency binaries, and installed binary caches.</li> <li>Tightened provider dependency provenance so wrapper providers now record the upstream runtimes they actually depend on (<code>node</code>, <code>python</code>, <code>ruby</code>, installer binaries) instead of flattening everything into the active provider.</li> <li>Improved <code>run --script</code> option merging so same-name script dependencies now contribute defaults to the final run binary without overriding an explicit <code>--binproviders</code> / <code>ABXPKG_BINPROVIDERS</code> selection.</li> <li>Hardened the base provider action flow so nullable security options are resolved to real provider/action defaults before handlers run, instead of leaking <code>None</code> into provider-specific install/update code.</li> </ul> <h2>🧭 Quick Examples</h2> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="abxpkg version abxpkg version yt-dlp abxpkg list abxpkg list env playwright chromium"><pre>abxpkg version abxpkg version yt-dlp abxpkg list abxpkg list env playwright chromium</pre></div> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="abxpkg --binproviders=env,uv,pip run yt-dlp --version abx --global yt-dlp --version"><pre>abxpkg --binproviders=env,uv,pip run yt-dlp --version abx --global yt-dlp --version</pre></div> <div class="highlight highlight-source-js notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="#!/usr/bin/env -S abxpkg run --script node // /// script // dependencies = [ // {name = &quot;node&quot;, binproviders = [&quot;env&quot;, &quot;brew&quot;], min_version = &quot;22.0.0&quot;}, // {name = &quot;playwright&quot;, binproviders = [&quot;playwright&quot;, &quot;pnpm&quot;, &quot;npm&quot;, &quot;yarn&quot;]}, // ] // ///"><pre>#!/usr/bin/env -S abxpkg run --script node <span class="pl-c">// /// script</span> <span class="pl-c">// dependencies = [</span> <span class="pl-c">// {name = "node", binproviders = ["env", "brew"], min_version = "22.0.0"},</span> <span class="pl-c">// {name = "playwright", binproviders = ["playwright", "pnpm", "npm", "yarn"]},</span> <span class="pl-c">// ]</span> <span class="pl-c">// ///</span></pre></div> <h2>🛠 What Changed</h2> <ul> <li>Added documented <code>abxpkg version</code> / <code>abxpkg list</code> flows and refreshed the generated docs/site output to match the current provider/runtime model.</li> <li>Refined cache handling so provider-local <code>derived.env</code> entries preserve stable absolute paths, create missing cache directories lazily, and de-duplicate repeated installer/binary lines in global listings.</li> <li>Fixed <code>Binary._binprovider_order()</code> so cached providers are preferred without dropping uncached fallback providers during update/uninstall flows.</li> <li>Made no-op providers like <code>env</code> and <code>bash</code> still resolve and validate binaries during <code>install()</code> / <code>update()</code>, including enforcing <code>min_version</code> on the final loaded binary instead of silently accepting a mismatch.</li> <li>Resolved nullable <code>postinstall_scripts</code> / <code>min_release_age</code> in the base <code>BinProvider.install()</code> / <code>update()</code> / <code>uninstall()</code> path using provider/action defaults, while preserving warnings for unsupported strict values.</li> <li>Tightened installer provenance so <code>INSTALLER_BINARY()</code> now preserves the real upstream provider that loaded the installer binary, instead of re-wrapping everything as if it came from the active provider.</li> <li>Ensured explicit <code>--binproviders</code> / <code>ABXPKG_BINPROVIDERS</code> remain an exact provider allowlist/order during installer and dependency resolution, instead of silently widening back to defaults.</li> <li>Added explicit upstream dependency tracking for wrapper providers that really depend on another runtime binary: <ul> <li><code>npm</code>, <code>pnpm</code>, <code>yarn</code>, <code>playwright</code>, and <code>puppeteer</code> now cache <code>node</code></li> <li><code>pip</code>, <code>ansible</code>, and <code>pyinfra</code> now cache <code>python</code></li> <li><code>gem</code> now caches <code>ruby</code></li> </ul> </li> <li>Fixed <code>GoGetProvider</code> installer resolution so <code>go</code> is loaded through a proper <code>go version</code> override instead of relying on generic <code>--version</code> probing.</li> <li>Tightened <code>BrewProvider</code> behavior so <code>postinstall_scripts=False</code> is only claimed for <code>brew install</code>, not <code>brew upgrade</code>, which has no equivalent <code>--skip-post-install</code> flag.</li> <li>Improved script-mode dependency merging so same-name dependencies (for example <code>node</code> in <code>run --script node</code>) merge their defaults into the final run binary generically instead of only special-casing <code>min_version</code>.</li> <li>Updated provider summaries and list/version output so installer binaries, upstream dependency binaries, and installed binaries are reported more accurately and with less duplication.</li> </ul> <h2><g-emoji class="g-emoji" alias="warning">⚠️</g-emoji> Behavioral Changes</h2> <ul> <li>Explicit provider selection now stays explicit. If you pass <code>--binproviders=...</code> or set <code>ABXPKG_BINPROVIDERS</code>, dependency and installer resolution no longer silently re-add default providers behind your back.</li> <li><code>install()</code> / <code>update()</code> on read-only/no-op providers still behave as no-ops for mutation, but they now validate the resolved binary and enforce <code>min_version</code> on the result.</li> <li>Passing nullable security fields through provider instances or provider overrides is safer now: <code>None</code> means “use the provider/action default”, not “let a provider handler crash on an assertion”.</li> </ul> pirate tag:github.com,2008:Repository/802422164/v1.10.2 2026-04-13T11:06:33Z v1.10.2 <h1>abxpkg v1.10.2</h1> <h2>✨ Highlights</h2> <ul> <li>Renamed the project from <code>abx-pkg</code> / <code>abx_pkg</code> to <code>abxpkg</code>, including the Python package name, docs, examples, and release surface.</li> <li>Added a much richer CLI runtime model around <code>abxpkg run</code>, <code>abx</code>, and <code>abxpkg run --script</code>, with consistent provider ENV/PATH merging for real subprocess execution.</li> <li>Added provider-local <code>derived.env</code> caches for resolved binaries and installer binaries, including <code>version</code>, <code>sha256</code>, <code>mtime</code>, and <code>euid</code> tracking.</li> <li>Tightened provider ownership and provenance reporting so installer binaries, upstream dependency binaries, and installed binaries are surfaced more explicitly.</li> <li>Simplified provider state: much more work now happens lazily at <code>setup()</code> / first-use time instead of during import or construction.</li> </ul> <h2>🧭 Quick Examples</h2> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="pip install abxpkg abxpkg --global install yt-dlp abx --binproviders=env,uv,pip,brew yt-dlp --version"><pre>pip install abxpkg abxpkg --global install yt-dlp abx --binproviders=env,uv,pip,brew yt-dlp --version</pre></div> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="abxpkg --min-version=1.2.3 --min-release-age=7 install yt-dlp abxpkg --overrides='{&quot;pip&quot;:{&quot;install_args&quot;:[&quot;yt-dlp[default]&quot;]}}' install yt-dlp abxpkg --install-args='[&quot;black==24.2.0&quot;]' install black"><pre>abxpkg --min-version=1.2.3 --min-release-age=7 install yt-dlp abxpkg --overrides=<span class="pl-s"><span class="pl-pds">'</span>{"pip":{"install_args":["yt-dlp[default]"]}}<span class="pl-pds">'</span></span> install yt-dlp abxpkg --install-args=<span class="pl-s"><span class="pl-pds">'</span>["black==24.2.0"]<span class="pl-pds">'</span></span> install black</pre></div> <div class="highlight highlight-source-js notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="#!/usr/bin/env -S abxpkg run --script node // /// script // dependencies = [ // {name = &quot;node&quot;, binproviders = [&quot;env&quot;, &quot;apt&quot;, &quot;brew&quot;], min_version = &quot;22.0.0&quot;}, // {name = &quot;playwright&quot;, binproviders = [&quot;pnpm&quot;, &quot;npm&quot;]}, // ] // ///"><pre>#!/usr/bin/env -S abxpkg run --script node <span class="pl-c">// /// script</span> <span class="pl-c">// dependencies = [</span> <span class="pl-c">// {name = "node", binproviders = ["env", "apt", "brew"], min_version = "22.0.0"},</span> <span class="pl-c">// {name = "playwright", binproviders = ["pnpm", "npm"]},</span> <span class="pl-c">// ]</span> <span class="pl-c">// ///</span></pre></div> <h2>🛠 What Changed</h2> <ul> <li>Reworked the core provider engine around the new <code>abxpkg/</code> package layout and a much larger <code>BinProvider</code> / <code>Binary</code> runtime surface.</li> <li>Added <code>loaded_mtime</code> and <code>loaded_euid</code> alongside <code>loaded_abspath</code>, <code>loaded_version</code>, and <code>loaded_sha256</code>, and threaded them through provider caches, summaries, and binary models.</li> <li>Added provider-local <code>derived.env</code> metadata caching, installer caching, and dependency caching so repeated loads can skip expensive version probes when the fingerprint still matches.</li> <li>Standardized <code>pip</code> and <code>uv</code> install-root layouts so hermetic environments live at <code>&lt;install_root&gt;/venv</code> while provider metadata stays at <code>&lt;install_root&gt;</code>.</li> <li>Hardened install semantics so package-manager success only counts if a runnable binary is actually produced; failed installs now roll back generically in the base provider flow.</li> <li>Split runtime dependency reporting into clearer concepts like <code>INSTALLER_BINARY</code>, <code>depends_on_binaries</code>, and <code>installed_binaries</code>.</li> <li>Extended the CLI with <code>--global</code> as a thin alias for <code>--lib=None</code>, hidden <code>upgrade</code> aliases, richer provider/version reporting, and direct handler-style override flags such as <code>--install-args</code>, <code>--version</code>, <code>--abspath</code>, and <code>--packages</code>.</li> <li>Improved <code>abx</code> so it stays a very thin wrapper over <code>abxpkg run --install ...</code> while still forwarding the expanded CLI surface correctly.</li> <li>Added inline <code>/// script</code> dependency parsing for <code>abxpkg run --script</code>, including <code>[tool.abxpkg]</code> env injection and dependency provider ENV/PATH merging before script execution.</li> <li>Reworked logging output and CLI rendering substantially: quieter non-debug failures, better subprocess output formatting, better method highlighting, and richer provider/version summaries.</li> </ul> <h2><g-emoji class="g-emoji" alias="warning">⚠️</g-emoji> Behavioral Changes</h2> <ul> <li>The package/import surface is now <code>abxpkg</code>, not <code>abx-pkg</code> / <code>abx_pkg</code>.</li> <li>CLI managed mode is now the default; use <code>--global</code> or <code>--lib=None</code> to force provider global mode.</li> <li><code>load()</code> / <code>install()</code> correctness is stricter: providers no longer get to report success unless they can resolve a runnable binary afterward.</li> <li>Provider ownership/provenance is less hand-wavy now: upstream installer/dependency binaries are tracked separately from installed binaries.</li> </ul> pirate tag:github.com,2008:Repository/802422164/v1.9.30 2026-04-12T19:39:52Z v1.9.30 <h1>abx-pkg v1.9.30</h1> <h2>✨ Highlights</h2> <ul> <li>Added <code>abx-pkg run --script</code>, which reads inline <code>/// script</code> metadata blocks so scripts can declare binary dependencies and <code>tool.abx-pkg</code> settings right at the top of the file.</li> <li>Unified managed providers around shared <code>install_root</code> / <code>bin_dir</code> behavior, and made <code>ABX_PKG_LIB_DIR</code> resolve from the live environment so CLI <code>--lib</code> overrides behave consistently.</li> <li>Added first-class <code>--no-cache</code> and <code>--debug</code> CLI controls, and tightened the shared binary lifecycle so <code>load()</code> / <code>install()</code> / <code>update()</code> / <code>uninstall()</code> all speak the same cache semantics.</li> <li>Fixed several installer-resolution and recursion edge cases, while making the real Playwright and Puppeteer test paths much faster instead of faking them.</li> </ul> <h2>🧭 Quick Examples</h2> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="abx-pkg --lib=/tmp/abx --no-cache install yt-dlp abx-pkg --debug --binproviders=env,npm,playwright run --script node ./capture.js"><pre>abx-pkg --lib=/tmp/abx --no-cache install yt-dlp abx-pkg --debug --binproviders=env,npm,playwright run --script node ./capture.js</pre></div> <div class="highlight highlight-source-js notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="#!/usr/bin/env -S abx-pkg run --script node // /// script // dependencies = [ // {name = &quot;playwright&quot;, binproviders = [&quot;npm&quot;, &quot;pnpm&quot;]}, // {name = &quot;chromium&quot;, binproviders = [&quot;playwright&quot;, &quot;puppeteer&quot;, &quot;apt&quot;], min_version = &quot;131.0.0&quot;}, // ] // [tool.abx-pkg] // ABX_PKG_POSTINSTALL_SCRIPTS = true // ///"><pre>#!/usr/bin/env -S abx-pkg run --script node <span class="pl-c">// /// script</span> <span class="pl-c">// dependencies = [</span> <span class="pl-c">// {name = "playwright", binproviders = ["npm", "pnpm"]},</span> <span class="pl-c">// {name = "chromium", binproviders = ["playwright", "puppeteer", "apt"], min_version = "131.0.0"},</span> <span class="pl-c">// ]</span> <span class="pl-c">// [tool.abx-pkg]</span> <span class="pl-c">// ABX_PKG_POSTINSTALL_SCRIPTS = true</span> <span class="pl-c">// ///</span></pre></div> <h2>🛠 What Changed</h2> <ul> <li><code>parse_script_metadata()</code> and <code>run --script</code> now parse comment-prefix-agnostic <code>/// script</code> blocks, resolve declared dependencies before execution, merge <code>[tool.abx-pkg]</code> settings, and preserve child exit codes/stdout/stderr cleanly.</li> <li>The provider constructor surface now consistently prefers <code>install_root</code> and <code>bin_dir</code>, while legacy provider-specific root aliases are still accepted through validation aliases.</li> <li><code>abx_pkg_install_root_default()</code> now reads <code>ABX_PKG_LIB_DIR</code> from the live environment instead of a module-import snapshot, so CLI <code>--lib</code> and runtime env overrides propagate correctly across providers.</li> <li>Removed <code>load_or_install</code> from the public API / CLI in favor of <code>install()</code>, and promoted <code>no_cache</code> into the shared lifecycle surface for <code>Binary</code> and <code>BinProvider</code>.</li> <li>Hardened installer resolution across providers: fixed <code>detect_euid()</code> recursion, fixed dry-run version probing, corrected Go <code>PATH</code> / env handling, restored Yarn Berry <code>--force</code> behavior for <code>no_cache</code>, and normalized installer-binary abspath handling.</li> <li>Playwright and Puppeteer now share the cleaned <code>install_root</code> / <code>bin_dir</code> model, bootstrap their installer binaries more predictably, and reuse seeded real browser installs in tests to cut redundant downloads.</li> <li>CI now provisions both Yarn classic and Yarn Berry explicitly, pins pnpm to <code>10.19.0</code>, and uses workflow concurrency cancellation plus job timeouts to prevent stale runs from piling up.</li> <li>README and generated docs were refreshed to match the new CLI, lifecycle, and managed-root behavior.</li> </ul> <h2><g-emoji class="g-emoji" alias="warning">⚠️</g-emoji> Behavioral Changes</h2> <ul> <li>Use <code>Binary.install()</code> / <code>abx-pkg install</code> instead of <code>load_or_install</code>.</li> <li>CLI logging now defaults to <code>INFO</code>; enable debug output explicitly with <code>--debug</code> or <code>ABX_PKG_DEBUG=1</code>.</li> <li><code>--no-cache</code> / <code>ABX_PKG_NO_CACHE=1</code> now apply consistently across <code>load()</code>, <code>install()</code>, <code>update()</code>, <code>uninstall()</code>, and <code>run</code>.</li> </ul> <h2>🧪 Verification</h2> <ul> <li><code>uv run prek run --all-files</code> passed on the release commit.</li> <li>Focused real-provider coverage was exercised for Playwright, Puppeteer, Bun, pnpm, Yarn classic, Yarn Berry, and GoGet lifecycle paths.</li> </ul> <p>Thanks to everyone pushing on the install-root cleanup, browser provider edge cases, and CLI ergonomics. 🛠️</p> pirate tag:github.com,2008:Repository/802422164/v1.9.29 2026-04-10T06:31:12Z v1.9.29 <h1>abx-pkg v1.9.29</h1> <h2>✨ Highlights</h2> <ul> <li>Added <code>abx-pkg run</code>, a direct exec path that resolves a binary through the configured providers and then hands off execution cleanly.</li> <li>Added <code>abx</code>, a thin <code>abx-pkg --install run ...</code> alias that behaves like a cross-provider <code>npx</code> / <code>uvx</code> / <code>pipx run</code>.</li> <li>Unified provider install-root defaults around <code>ABX_PKG_LIB_DIR</code>, provider-specific <code>ABX_PKG_&lt;NAME&gt;_ROOT</code> overrides, and a platform-aware default lib dir.</li> <li>Added a generated GitHub Pages landing page with a docs build pipeline and a much more structured README.</li> <li>Made provider behavior more explicit by removing silent <code>uv</code> / <code>pnpm</code> auto-switching from <code>PipProvider</code> and <code>NpmProvider</code>.</li> </ul> <h2>🧭 Quick Examples</h2> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="abx yt-dlp --help abx --binproviders=env,uv,pip,brew yt-dlp --version abx-pkg --binproviders=pip --install run black --version"><pre>abx yt-dlp --help abx --binproviders=env,uv,pip,brew yt-dlp --version abx-pkg --binproviders=pip --install run black --version</pre></div> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="export ABX_PKG_LIB_DIR=~/.config/abx/lib export ABX_PKG_PIP_ROOT=~/.cache/abx/pip abx-pkg --binproviders=pip,uv install black abx-pkg --postinstall-scripts=False --min-release-age=7 install yt-dlp"><pre><span class="pl-k">export</span> ABX_PKG_LIB_DIR=<span class="pl-k">~</span>/.config/abx/lib <span class="pl-k">export</span> ABX_PKG_PIP_ROOT=<span class="pl-k">~</span>/.cache/abx/pip abx-pkg --binproviders=pip,uv install black abx-pkg --postinstall-scripts=False --min-release-age=7 install yt-dlp</pre></div> <h2>🛠 What Changed</h2> <ul> <li>Exposed the full <code>Binary</code> / <code>BinProvider</code> configuration surface on the CLI, including install roots, timeouts, release-age controls, postinstall-script policy, and overrides.</li> <li>Hardened the new <code>run</code> / <code>abx</code> command path for macOS, <code>--</code> handling, bare boolean flags, and child-arg forwarding.</li> <li>Switched the centralized default lib dir to <code>platformdirs</code>, while keeping explicit kwargs and provider-specific env vars highest priority.</li> <li>Landed a GitHub Pages deployment workflow, docs renderer, and generated landing page for the provider matrix and API surface.</li> <li>Propagated security flags to Playwright bootstrap installs and tightened several provider-specific install-root edge cases.</li> <li>Expanded test coverage heavily, especially around the CLI, install-root precedence, and real subprocess execution.</li> </ul> <h2><g-emoji class="g-emoji" alias="warning">⚠️</g-emoji> Behavioral Changes</h2> <ul> <li><code>PipProvider</code> no longer silently falls through to <code>uv</code>; choose <code>UvProvider</code> explicitly when you want <code>uv</code> semantics.</li> <li><code>NpmProvider</code> no longer silently falls through to <code>pnpm</code>; choose <code>PnpmProvider</code> explicitly when you want <code>pnpm</code> semantics.</li> <li>Providers with isolated install roots now follow one clear precedence order: explicit kwargs &gt; <code>ABX_PKG_&lt;NAME&gt;_ROOT</code> &gt; <code>ABX_PKG_LIB_DIR/&lt;name&gt;</code> &gt; provider default.</li> </ul> <h2>🧪 Verification</h2> <ul> <li>GitHub Actions passed on <code>main</code> for the release line before the version bump.</li> <li>Local checks passed with <code>uv run pyright</code> and focused <code>uv run pytest</code> slices covering the new CLI/install-root work.</li> </ul> <p>Thanks to everyone pushing on the provider edge cases and CLI ergonomics. 🚀</p> pirate tag:github.com,2008:Repository/802422164/v1.9.28 2026-04-09T09:52:34Z v1.9.28 <h1>abx-pkg v1.9.28</h1> <h2>✨ Highlights</h2> <ul> <li>Added dedicated providers for <code>uv</code>, <code>pnpm</code>, <code>yarn</code>, <code>bun</code>, <code>deno</code>, and Playwright browser installs, and exported them from the public <code>abx_pkg</code> API.</li> <li>Added a real <code>abx-pkg</code> CLI built with <code>rich-click</code>, including <code>version</code>, <code>install</code>, <code>update</code>, <code>uninstall</code>, <code>load</code>, and <code>load_or_install</code>, plus <code>--lib</code>, <code>--binproviders</code>, and <code>--dry-run</code>.</li> <li>Added centralized install-root defaults via <code>ABX_PKG_LIB_DIR</code>, with per-provider <code>ABX_PKG_&lt;NAME&gt;_ROOT</code> overrides across providers that manage their own install roots.</li> </ul> <h2>🧰 What Changed</h2> <ul> <li><code>UvProvider</code> now stands on its own instead of piggybacking on <code>PipProvider</code>, with support for both hermetic venv installs and <code>uv tool</code> mode.</li> <li><code>PnpmProvider</code>, <code>YarnProvider</code>, <code>BunProvider</code>, and <code>DenoProvider</code> each got dedicated implementations with their own install/update/uninstall logic, managed prefixes, and provider-specific security flag handling.</li> <li>Added <code>PlaywrightProvider</code> for browser artifact installs, alongside follow-up improvements to browser-provider path handling and install/load coverage.</li> <li>Provider defaults now honor <code>ABX_PKG_LIB_DIR</code> and provider-specific root env vars consistently, and the repo now includes end-to-end tests covering precedence and on-disk install locations.</li> <li>The generic version probe now skips non-zero <code>--version</code> exits instead of misreading their stderr, and <code>PipProvider</code> now falls back to package metadata when a console script refuses version flags.</li> <li>Ansible and Pyinfra package-install paths were hardened for real-world privilege boundaries, including better interpreter selection for apt-backed Ansible runs and safer brew drop-privilege handling.</li> <li>Packaging metadata was refreshed to ship the console script cleanly and include the new CLI dependency and build layout changes.</li> </ul> <h2>🧪 Quality &amp; Docs</h2> <ul> <li>CI now provisions Yarn 4 via corepack, Bun, Deno, Go, and richer environment diagnostics so the expanded provider matrix is exercised more realistically.</li> <li>Added broad new provider and CLI test coverage, including dedicated suites for <code>uv</code>, <code>pnpm</code>, <code>yarn</code>, <code>bun</code>, <code>deno</code>, <code>playwright</code>, and <code>ABX_PKG_LIB_DIR</code>.</li> <li>README docs were expanded to cover the new providers, environment-variable install-root behavior, and the new CLI, with the Django-specific guidance folded into a single collapsible section.</li> </ul> <p>Thanks to everyone stress-testing the edge cases that made this release sharper. 🛠️</p> pirate tag:github.com,2008:Repository/802422164/v1.9.25 2026-04-03T06:58:41Z v1.9.25: Rename CustomProvider to BashProvider <p>Highlights</p> <ul> <li>Renamed the shell-command provider from <code>CustomProvider</code> / <code>custom</code> to <code>BashProvider</code> / <code>bash</code>.</li> <li>Renamed the provider module to <code>abx_pkg.binprovider_bash</code>, updated lazy exports/imports, and switched the managed-root config from <code>ABX_PKG_CUSTOM_ROOT</code> to <code>ABX_PKG_BASH_ROOT</code>.</li> <li>Renamed provider-specific fields and exported shell env vars to <code>bash_root</code>, <code>bash_bin_dir</code>, <code>BASH_INSTALL_ROOT</code>, and <code>BASH_BIN_DIR</code>.</li> </ul> <p>Behavior</p> <ul> <li>Preserved the existing shell-command install/update/uninstall model while keeping <code>install_root</code> and <code>bin_dir</code> aliases working for the renamed provider.</li> <li>Updated the provider lifecycle and security-control tests to exercise the renamed <code>bash</code> provider end to end.</li> <li>Fixed Puppeteer's internal installer binary naming to <code>puppeteer-browsers</code> so the documented/provider-facing name matches the actual binary being bootstrapped.</li> </ul> <p>Documentation</p> <ul> <li>Refreshed the README provider list and binprovider sections so the security-option docs match the current implementation.</li> <li>Added and corrected documentation for <code>bash</code>, <code>chromewebstore</code>, and <code>puppeteer</code>, including provider defaults, env-backed security controls, and unsupported-option warning behavior.</li> </ul> <p>Upgrade notes</p> <ul> <li>Replace <code>CustomProvider</code> imports with <code>BashProvider</code>.</li> <li>Replace provider name <code>custom</code> with <code>bash</code> in <code>Binary.overrides</code> and any serialized config.</li> <li>Replace <code>custom_root</code> / <code>custom_bin_dir</code> with <code>bash_root</code> / <code>bash_bin_dir</code>.</li> <li>Replace <code>ABX_PKG_CUSTOM_ROOT</code> with <code>ABX_PKG_BASH_ROOT</code>.</li> </ul> pirate tag:github.com,2008:Repository/802422164/v1.9.24 2026-04-03T06:43:17Z v1.9.24 <h2>Highlights</h2> <ul> <li>Added three new first-class providers: <code>ChromeWebstoreProvider</code>, <code>PuppeteerProvider</code>, and <code>CustomProvider</code>.</li> <li>Packaged the Chrome/extension JS runtime directly inside <code>abx-pkg</code>, so Chrome Web Store installs now work without depending on a sibling <code>abx-plugins</code> checkout.</li> <li>Reworked provider option precedence so per-call args override <code>Binary(...)</code>, and <code>Binary(...)</code> overrides provider defaults, with cleaner handling for <code>dry_run</code>, <code>postinstall_scripts</code>, and <code>min_release_age</code>.</li> <li>Improved privilege escalation and subprocess error reporting across providers, including preserving failed <code>sudo</code> output when a fallback attempt also fails.</li> <li>Parallelized CI to run one test file per job with auto-discovered live lifecycle coverage.</li> </ul> <h2>New Providers</h2> <h3><code>ChromeWebstoreProvider</code></h3> <ul> <li>Added a dedicated Chrome Web Store provider in <code>abx_pkg/binprovider_chromewebstore.py</code>.</li> <li>Supports <code>install_root</code> / <code>bin_dir</code> via <code>extensions_root</code> / <code>extensions_dir</code>.</li> <li>Installs extensions into a managed cache and resolves the installed binary to the unpacked <code>manifest.json</code>.</li> <li>Ships the required JS runtime and config files inside the package: <ul> <li><code>abx_pkg/js/base/config.json</code></li> <li><code>abx_pkg/js/base/utils.js</code></li> <li><code>abx_pkg/js/chrome/config.json</code></li> <li><code>abx_pkg/js/chrome/chrome_utils.js</code></li> </ul> </li> <li>Includes real lifecycle tests covering provider and <code>Binary(...)</code> flows.</li> </ul> <h3><code>PuppeteerProvider</code></h3> <ul> <li>Added a dedicated Puppeteer/browser provider in <code>abx_pkg/binprovider_puppeteer.py</code>.</li> <li>Supports provider-managed install roots and bin dirs for <code>@puppeteer/browsers</code> installs.</li> <li>Handles generic browser install args instead of forcing a Chrome-only abstraction.</li> <li>Fixed installed-browser resolution to use semantic version ordering rather than lexicographic string sorting.</li> <li>Includes real lifecycle tests plus regression coverage for version ordering.</li> </ul> <h3><code>CustomProvider</code></h3> <ul> <li>Added a dedicated <code>CustomProvider</code> built on top of <code>EnvProvider</code> for shell-command installs.</li> <li>Supports <code>install_root</code> / <code>bin_dir</code> via <code>custom_root</code> / <code>custom_bin_dir</code>.</li> <li>Uses literal per-binary shell overrides for install/update/uninstall while still participating in the standard <code>Binary</code>/<code>BinProvider</code> lifecycle.</li> <li>Includes real lifecycle coverage for direct provider and <code>Binary(...)</code> usage.</li> </ul> <h2>Core Behavior Changes</h2> <h3>Provider and Binary option precedence</h3> <ul> <li>Added consistent per-call <code>dry_run</code> support to <code>install()</code>, <code>update()</code>, <code>uninstall()</code>, and <code>load_or_install()</code>.</li> <li>Standardized precedence so: <ul> <li>explicit action args win</li> <li><code>Binary(...)</code> defaults come next</li> <li>provider defaults come last</li> </ul> </li> <li>Exposed env-backed defaults for: <ul> <li><code>ABX_PKG_INSTALL_TIMEOUT</code></li> <li><code>ABX_PKG_VERSION_TIMEOUT</code></li> <li><code>ABX_PKG_DRY_RUN</code> (preferred over <code>DRY_RUN</code> when both are set)</li> </ul> </li> </ul> <h3>Security controls</h3> <ul> <li>Provider-wide defaults for <code>min_release_age</code> / <code>postinstall_scripts</code> now only hydrate from env vars on providers that actually support those controls.</li> <li>Unsupported providers no longer fail closed by default when these options are present.</li> <li>Instead, unsupported explicit values now warn and continue.</li> <li><code>EnvProvider</code> no longer claims support for install-only security controls it cannot enforce.</li> <li><code>pip</code> and <code>npm</code> install-arg merging now preserves explicitly supplied conflicting flags instead of blindly overriding them.</li> </ul> <h3>API cleanup</h3> <ul> <li><code>binproviders</code> is now the canonical field name used throughout docs/examples instead of <code>binproviders_supported</code>.</li> <li>Module API normalization now handles both provider classes and provider instances consistently.</li> <li>Unavailable-provider errors now use the generic wording: <ul> <li><code>XProvider is disabled because &lt;installer&gt; is not available on this host</code></li> </ul> </li> </ul> <h2>Subprocess and Privilege Handling</h2> <ul> <li>Centralized subprocess error logging in the shared <code>_raise_proc_error(...)</code> path.</li> <li>Reworked older providers to use shared subprocess error handling instead of open-coded log+raise branches.</li> <li>Updated shared <code>exec()</code> behavior to attempt privilege escalation when the provider needs a different EUID, while still falling back to the unprivileged path when escalation is unavailable.</li> <li>When both a <code>sudo</code> attempt and a fallback attempt fail, the final error now includes both outputs.</li> <li>Fixed ansible/pyinfra tempdir cleanup when privileged subprocesses leave root-owned files behind.</li> </ul> <h2>Provider-specific Improvements</h2> <ul> <li><code>AptProvider</code>, <code>BrewProvider</code>, <code>CargoProvider</code>, <code>GemProvider</code>, <code>GoGetProvider</code>, <code>NixProvider</code>, <code>PipProvider</code>, <code>NpmProvider</code>, <code>PyinfraProvider</code>, <code>AnsibleProvider</code>, and <code>DockerProvider</code> now rely more consistently on shared subprocess/error handling.</li> <li><code>PipProvider</code> and <code>NpmProvider</code> now merge security controls with explicit install args more rigorously.</li> <li><code>BrewProvider</code> respects explicit <code>--skip-post-install</code> args when present.</li> <li><code>PipProvider</code> and <code>NpmProvider</code> gained stronger tests around provider defaults vs per-call overrides.</li> </ul> <h2>Packaging and Tooling</h2> <ul> <li>Added wheel/sdist inclusion rules for packaged JS assets in <code>pyproject.toml</code>.</li> <li>Added <code>bin/setup_monorepo.sh</code> for local monorepo setup.</li> <li>Updated the README to document the new providers, env vars, canonical <code>binproviders</code> field name, and current provider behavior.</li> </ul> <h2>CI and Test Coverage</h2> <ul> <li>Switched the main test workflow to one-job-per-file parallelization.</li> <li>Live lifecycle tests are now auto-discovered from the actual test files instead of being hard-coded.</li> <li>Reduced the standard matrix to: <ul> <li>Linux: Python 3.11, 3.14</li> <li>macOS: Python 3.13</li> </ul> </li> <li>Added new provider integration suites for: <ul> <li><code>chromewebstore</code></li> <li><code>custom</code></li> <li><code>puppeteer</code></li> </ul> </li> <li>Expanded coverage for: <ul> <li>module API normalization</li> <li>env-backed security defaults</li> <li>unsupported security option warning behavior</li> <li>provider-vs-action override precedence</li> </ul> </li> </ul> pirate tag:github.com,2008:Repository/802422164/v1.9.23 2026-04-02T16:38:18Z v1.9.23 <h1>abx-pkg v1.9.23</h1> <h2>Highlights</h2> <ul> <li>🧪 Replaced the old single-file <code>tests.py</code> runner with a real <code>pytest</code> suite under <code>tests/</code>, with live lifecycle coverage across <code>apt</code>, <code>brew</code>, <code>pip</code>, <code>npm</code>, <code>cargo</code>, <code>gem</code>, <code>goget</code>, <code>nix</code>, <code>docker</code>, <code>pyinfra</code>, and <code>ansible</code>.</li> </ul> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="uv run pytest -m &quot;not root_required and not docker_required&quot;"><pre>uv run pytest -m <span class="pl-s"><span class="pl-pds">"</span>not root_required and not docker_required<span class="pl-pds">"</span></span></pre></div> <ul> <li>🧭 Standardized isolated install layout across providers with shared <code>install_root</code> / <code>bin_dir</code> aliases, while still supporting provider-specific knobs like <code>pip_venv</code>, <code>npm_prefix</code>, <code>cargo_root</code>, <code>gem_home</code>, <code>gopath</code>, <code>nix_profile</code>, and <code>docker_shim_dir</code>.</li> </ul> <div class="highlight highlight-source-python notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="from pathlib import Path from abx_pkg import PipProvider provider = PipProvider(install_root=Path(&quot;/tmp/venv&quot;)) print(provider.install_root, provider.bin_dir)"><pre><span class="pl-k">from</span> <span class="pl-s1">pathlib</span> <span class="pl-k">import</span> <span class="pl-v">Path</span> <span class="pl-k">from</span> <span class="pl-s1">abx_pkg</span> <span class="pl-k">import</span> <span class="pl-v">PipProvider</span> <span class="pl-s1">provider</span> <span class="pl-c1">=</span> <span class="pl-en">PipProvider</span>(<span class="pl-s1">install_root</span><span class="pl-c1">=</span><span class="pl-en">Path</span>(<span class="pl-s">"/tmp/venv"</span>)) <span class="pl-en">print</span>(<span class="pl-s1">provider</span>.<span class="pl-c1">install_root</span>, <span class="pl-s1">provider</span>.<span class="pl-c1">bin_dir</span>)</pre></div> <ul> <li>⏱️ Centralized shared provider runtime behavior in <code>BinProvider</code>, including <code>install_timeout</code>, <code>version_timeout</code>, PATH propagation into subprocesses, deep-copy override handling, and safer cache-dir setup.</li> </ul> <div class="highlight highlight-source-python notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="from abx_pkg import NpmProvider provider = NpmProvider(install_timeout=120, version_timeout=10) binary = provider.install(&quot;zx&quot;)"><pre><span class="pl-k">from</span> <span class="pl-s1">abx_pkg</span> <span class="pl-k">import</span> <span class="pl-v">NpmProvider</span> <span class="pl-s1">provider</span> <span class="pl-c1">=</span> <span class="pl-en">NpmProvider</span>(<span class="pl-s1">install_timeout</span><span class="pl-c1">=</span><span class="pl-c1">120</span>, <span class="pl-s1">version_timeout</span><span class="pl-c1">=</span><span class="pl-c1">10</span>) <span class="pl-s1">binary</span> <span class="pl-c1">=</span> <span class="pl-s1">provider</span>.<span class="pl-c1">install</span>(<span class="pl-s">"zx"</span>)</pre></div> <h2>Provider Fixes</h2> <ul> <li>🔒 Fixed security override precedence so explicit <code>install_args</code> can adjust effective security behavior before fail-closed checks run, especially for npm <code>--ignore-scripts</code> and <code>--min-release-age=...</code>.</li> </ul> <div class="highlight highlight-source-python notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="from abx_pkg import NpmProvider provider = NpmProvider(min_release_age=36500).get_provider_with_overrides( overrides={&quot;zx&quot;: {&quot;install_args&quot;: [&quot;zx&quot;, &quot;--min-release-age=0&quot;]}}, )"><pre><span class="pl-k">from</span> <span class="pl-s1">abx_pkg</span> <span class="pl-k">import</span> <span class="pl-v">NpmProvider</span> <span class="pl-s1">provider</span> <span class="pl-c1">=</span> <span class="pl-en">NpmProvider</span>(<span class="pl-s1">min_release_age</span><span class="pl-c1">=</span><span class="pl-c1">36500</span>).<span class="pl-c1">get_provider_with_overrides</span>( <span class="pl-s1">overrides</span><span class="pl-c1">=</span>{<span class="pl-s">"zx"</span>: {<span class="pl-s">"install_args"</span>: [<span class="pl-s">"zx"</span>, <span class="pl-s">"--min-release-age=0"</span>]}}, )</pre></div> <ul> <li>🐳 Improved version detection for multiline banners by teaching <code>SemVer.parse(...)</code> to scan up to 5 lines. This fixes wrappers and tools whose version appears after a heading line, including Docker-backed command shims.</li> </ul> <div class="highlight highlight-source-python notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="from abx_pkg import SemVer SemVer.parse( &quot;ShellCheck - shell script analysis tool\nversion: v0.11.0-65-gcd41f79&quot; ) # -&gt; SemVer(&quot;0.11.0&quot;)"><pre><span class="pl-k">from</span> <span class="pl-s1">abx_pkg</span> <span class="pl-k">import</span> <span class="pl-v">SemVer</span> <span class="pl-v">SemVer</span>.<span class="pl-c1">parse</span>( <span class="pl-s">"ShellCheck - shell script analysis tool<span class="pl-cce">\n</span>version: v0.11.0-65-gcd41f79"</span> ) <span class="pl-c"># -&gt; SemVer("0.11.0")</span></pre></div> <ul> <li>🧰 Tightened provider-specific behavior across the built-ins: <ul> <li><code>apt</code> / <code>brew</code> helper backends now use resolved <code>install_args</code></li> <li><code>cargo uninstall</code> no longer reuses incompatible version-pinned install flags</li> <li><code>nix uninstall</code> preserves other entries in the same profile</li> <li><code>goget</code> is now the canonical provider name throughout the package and docs</li> <li><code>Binary.abspaths</code> is available as a backward-compatible read alias for <code>loaded_abspaths</code></li> </ul> </li> </ul> <h2>Docs And DX</h2> <ul> <li>📚 Refreshed the README API reference with verified provider defaults, install roots, security controls, timeout behavior, override support, and direct source/test links.</li> <li>🛠️ Updated the development workflow docs to match the current toolchain and test layout.</li> </ul> <div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="uv sync --all-extras --all-groups uv run prek run --all-files uv run pytest -sx tests/"><pre>uv sync --all-extras --all-groups uv run prek run --all-files uv run pytest -sx tests/</pre></div> pirate tag:github.com,2008:Repository/802422164/v1.9.22 2026-04-02T07:34:44Z v1.9.22 <h2>✨ Highlights</h2> <ul> <li> <p>🔒 <strong>Security defaults now propagate consistently across binaries and providers.</strong></p> <ul> <li><code>BinProvider</code> now owns default <code>postinstall_scripts</code> and <code>min_release_age</code> values, and <code>Binary</code> inherits them automatically when you don't override them explicitly.</li> <li>Unsupported providers now fail closed instead of silently ignoring security constraints.</li> </ul> <div class="highlight highlight-source-python notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="provider = EnvProvider(postinstall_scripts=True, min_release_age=4) binary = Binary(name=&quot;python&quot;, binproviders=[provider]) assert binary.postinstall_scripts is True assert binary.min_release_age == 4"><pre><span class="pl-s1">provider</span> <span class="pl-c1">=</span> <span class="pl-en">EnvProvider</span>(<span class="pl-s1">postinstall_scripts</span><span class="pl-c1">=</span><span class="pl-c1">True</span>, <span class="pl-s1">min_release_age</span><span class="pl-c1">=</span><span class="pl-c1">4</span>) <span class="pl-s1">binary</span> <span class="pl-c1">=</span> <span class="pl-en">Binary</span>(<span class="pl-s1">name</span><span class="pl-c1">=</span><span class="pl-s">"python"</span>, <span class="pl-s1">binproviders</span><span class="pl-c1">=</span>[<span class="pl-s1">provider</span>]) <span class="pl-k">assert</span> <span class="pl-s1">binary</span>.<span class="pl-c1">postinstall_scripts</span> <span class="pl-c1">is</span> <span class="pl-c1">True</span> <span class="pl-k">assert</span> <span class="pl-s1">binary</span>.<span class="pl-c1">min_release_age</span> <span class="pl-c1">==</span> <span class="pl-c1">4</span></pre></div> </li> <li> <p>⬆️ <strong><code>min_version</code> is enforced end-to-end instead of only being advisory.</strong></p> <ul> <li><code>install()</code> and <code>update()</code> now validate the resolved version after the package manager runs.</li> <li><code>load_or_install()</code> will upgrade an already-installed binary when it exists but does not satisfy the requested minimum version.</li> </ul> <div class="highlight highlight-source-python notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="binary = provider.load_or_install(&quot;black&quot;, min_version=SemVer(&quot;24.0.0&quot;))"><pre><span class="pl-s1">binary</span> <span class="pl-c1">=</span> <span class="pl-s1">provider</span>.<span class="pl-c1">load_or_install</span>(<span class="pl-s">"black"</span>, <span class="pl-s1">min_version</span><span class="pl-c1">=</span><span class="pl-en">SemVer</span>(<span class="pl-s">"24.0.0"</span>))</pre></div> </li> <li> <p>📦 <strong>Provider install/update plumbing is more explicit and consistent.</strong></p> <ul> <li>Core handler signatures now thread <code>postinstall_scripts</code>, <code>min_release_age</code>, and <code>min_version</code> through setup/install/update paths.</li> <li><code>pip</code> and <code>npm</code> explicitly declare support for release-age and postinstall controls.</li> <li><code>brew</code> only uses Pyinfra/Ansible helper paths when postinstall scripts are allowed, and otherwise falls back to direct CLI invocations with the right flags.</li> <li>Timeout settings are preserved through provider copies via model fields instead of hidden underscored state.</li> </ul> </li> <li> <p>🧪 <strong>Tests were expanded around the new behavior and cleaned up for strict type-checking.</strong></p> <ul> <li>Added fail-closed coverage for providers that cannot honor <code>min_release_age</code> or disabled postinstall scripts.</li> <li>Added live tests for <code>pip</code> minimum-version upgrades and <code>npm</code> postinstall-script overrides.</li> <li>Tightened the test helper typing so <code>ty-check</code> and <code>pyright</code> pass without <code>cast</code>, <code>Any</code>, or <code>type: ignore</code> shortcuts.</li> </ul> <div class="highlight highlight-source-python notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="def is_install_args_sequence(value: object) -&gt; TypeGuard[InstallArgs]: return isinstance(value, (tuple, list)) and all(isinstance(item, str) for item in value)"><pre><span class="pl-k">def</span> <span class="pl-en">is_install_args_sequence</span>(<span class="pl-s1">value</span>: <span class="pl-smi">object</span>) <span class="pl-c1">-&gt;</span> <span class="pl-v">TypeGuard</span>[<span class="pl-smi">InstallArgs</span>]: <span class="pl-k">return</span> <span class="pl-en">isinstance</span>(<span class="pl-s1">value</span>, (<span class="pl-s1">tuple</span>, <span class="pl-s1">list</span>)) <span class="pl-c1">and</span> <span class="pl-en">all</span>(<span class="pl-en">isinstance</span>(<span class="pl-s1">item</span>, <span class="pl-s1">str</span>) <span class="pl-k">for</span> <span class="pl-s1">item</span> <span class="pl-c1">in</span> <span class="pl-s1">value</span>)</pre></div> </li> <li> <p>🏷️ <strong>Release metadata</strong></p> <ul> <li>Version bumped to <code>1.9.22</code>.</li> <li><code>uv.lock</code> refreshed to match the new package version.</li> </ul> </li> </ul> pirate